IronPython i platforma .NET – integracja  

Udostępnij na: Facebook

Autor: Bartosz Kierun

Opublikowano: 2011-02-18

W bieżącym artykule zajmiemy się możliwościami języka IronPython w kontekście jego integracji z platformą programistyczną .NET.

Platforma.NET oferuje programistom wiele możliwości, a skoro IronPython jest implementacją języka Python stworzoną właśnie na niej, byłoby dziwne, gdyby nie można było skorzystać z jej możliwości. Przypomnijmy tylko, że z punktu widzenia programisty najważniejszym elementem platformy .NET jest niezwykle bogaty zestaw bibliotek, pokrywający niemal każdy aspekt programowania, jaki można sobie wyobrazić. Ich wykorzystanie dzięki implementacji IronPythona staje się tak samo naturalne, jak podczas programowania w ściślej związanych z platformą .NET językach – C# czy Visual Basic .NET.

W dalszych częściach artykułu zajmiemy się zatem:

  • przykładem rozszerzenia języka IronPython z wykorzystaniem komponentu stworzonego w języka C#,
  • stworzeniem prostej aplikacji Windows Forms,
  • stworzeniem prostej aplikacji Windows Presentation Foundation,
  • możliwościami hostowania interpretera języka IronPython we własnych aplikacjach na platformie .NET.

Wprowadzenie

We wcześniejszych artykułach wspominaliśmy, że największą zaletą implementacji IronPythona jest jego integracja z platformą .NET. Taka integracja obejmuje wiele płaszczyzn – począwszy od wsparcia narzędziowego (środowisko programistyczne Visual Studio), a kończąc na wykorzystaniu środowiska uruchomieniowego CLR (Common Language Runtime). Wykorzystanie dojrzałego i wydajnego środowiska CLR gwarantuje nam nie tylko odpowiednią wydajność i stabilność wykonywania naszych programów, ale również wsparcie dla mechanizmów, które w standardowej implementacji języka Python nie były zbyt dobrze rozwiązane (kłopotliwa wielowątkowość, możliwość rozszerzania tylko poprzez język C). Dla typowego programisty, skupionego na szybkim tworzeniu funkcjonalnych programów i aplikacji, najważniejsza będzie jednak możliwość wykorzystania olbrzymiego zestawu bibliotek dostarczanych wraz z paczką instalacyjną .NET Framework.

Do najważniejszych technologii dostarczanych wraz z platformą w postaci zestawów bibliotek należą:

  • Base Class Library (BCL) – zestaw bibliotek standardowych oferujący możliwości takie jak: operacje I/O, programowanie wielowątkowe, kolekcje, operacje matematyczne itp.,
  • Data – dostęp do baz danych za pośrednictwem uniwersalnych sterowników – ODBC, OleDb, czy natywnych sterowników dostępowych do baz danych SQL Server czy Oracle,
  • XML – zestaw bibliotek umożliwiających korzystanie z technologii XML, XML Schema, XPath, XSLT, czy SOAP,
  • Windows Forms – podstawowa technologia do tworzenia interfejsów użytkownika na platformie Windows,
  • ASP.NET – technologia do tworzenia aplikacji webowych,
  • Windows Presentation Foundation (WPF) – najnowsza technologia do tworzenia interfejsów użytkownika na platformie Windows, oferująca dużo większe możliwości niż technologia Windows Forms zwłaszcza w zakresie grafiki 2D, 3D, animacji i całkowitego dostosowywania wyglądu pod względem szaty graficznej,
  • Windows Communication Foundation (WCF) – technologia umożliwiająca tworzenie wszelkiej maści aplikacji rozproszonych, wykorzystujących różne kanały komunikacyjne (TCP, http(s), potoki, kolejki wiadomości MSMQ) lub protokoły (binary, SOAP).

Poza wymienionymi technologiami, które z pewnością nie pokrywają wszystkich funkcjonalności oferowanych standardowo przez platformę .NET, programiści mają dodatkowo dostęp do szerokiego asortymentu darmowych i komercyjnych bibliotek pokrywających niemal każdy aspekt programowania. Innymi słowy, jeżeli Drogi Programisto zamierzasz napisać np. program przetwarzający dokumenty Office lub komunikujący się z serwerem pocztowym za pomocą protokołu MAPI – sprawdź najpierw, czy nie istnieją już gotowe komponenty umożliwiające osiągnięcie wymaganego rezultatu. Dobry programista lub architekt wie, że praca na dojrzałej i bardzo dobrze wspieranej – zarówno przez jej twórców, jak i firmy zewnętrzne lub społeczności – platformie programistycznej daje zazwyczaj dość dobre i przewidywalne rezultaty.

Ale wróćmy do samego języka Python, a konkretnie do możliwości jego rozszerzania. W jego natywnej implementacji w języku C rozszerzanie tegoż języka o własne funkcjonalności lub komponenty wymagało dosyć żmudnego programowania właśnie w języku C, co – nie ukrywajmy –  było dosyć trudne (zwłaszcza w porównaniu z łatwością programowania w samym języku Python). W opartej na platformie .NET implementacji  języka IronPython własne metody, klasy czy komponenty tworzy się tak samo łatwo jak w każdym innym, wspieranym przez tę platformę języku programowania. To oznacza, że każdy komponent stworzony np. w języku C# da się wykorzystać z poziomu języka IronPython bez najmniejszego problemu, a w dodatku bez żadnych dodatkowych warstw pośredniczących, konwersji typów danych czy marshallingu, co ma bardzo pozytywny wpływ na wydajność.

Tematy poruszane w tym artykule stanowią tak naprawdę wierzchołek góry lodowej – samo poznanie języka programowania (jego składni i semantyki) jest stosunkowo proste, natomiast eksploracja bibliotek standardowych to zajęcie na zdecydowanie dłuższy okres czasu. Jeżeli więc masz już Drogi Programisto doświadczenie z platformą .NET, to po krótkim zapoznaniu z językiem Python bardzo szybko będziesz mógł tworzyć nawet bardzo skomplikowane aplikacje, wykorzystując posiadaną już wiedzę. Dużo więcej pracy czeka osobę dopiero poznającą sam język oraz dodatkowo możliwości platformy .NET –  na dobrą sprawę o wielu jej składnikach i komponentach istnieją obszerne rozdziały w dokumentacji oraz osobne książki.

Główne składniki środowiska uruchomieniowego CLR

Równie ważną jak biblioteki standardowe częścią składową platformy .NET jest rozwijane już od wielu lat środowisko uruchomieniowe CLR (Common Language Runtime). Oferuje ono wiele ciekawych mechanizmów, których istnienie bardzo pozytywnie wpływa na stabilność, wydajność i bezpieczeństwo wykonywanych za jego pośrednictwem programów.

**Rys.1.Główne składniki środowiska uruchomieniowego CLR.

  • Memory Management – mechanizm odpowiedzialny za optymalne wykorzystanie pamięci przez aplikacje i programy.
  • Exception Handling – mechanizm obsługi błędów i wyjątków w aplikacjach, oparty na klauzulach try/catch/finally. Jest on znacznie wygodniejszy niż stosowane w wielu starszych językach programowania kody błędów.
  • Garbage Collector – to specjalna architektura zarządzania pamięcią, w której proces jej zwalniania odbywa się automatycznie, co z kolei zwalnia programistę z konieczności pamiętania o „niszczeniu” wykorzystanych w kodzie obiektów.
  • Reflection – to mechanizm pozwalający na modyfikację programu podczas jego działania. Możemy operować wtedy kodem, tak jak innymi danymi i zmiennymi w naszym programie.
  • JIT (Just-in-time) Compiler – metoda wykonywania programów, polegająca na kompilacji kodu pośredniego do kodu maszynowego „w locie”, czyli bezpośrednio przed jego wykonaniem.
  • Security Engine – zestaw mechanizmów odpowiedzialnych za bezpieczeństwo wykonywanego kodu. Sztandarowy mechanizm, czyli CAS (Code Access Security), pozwala na przyznawanie uprawnień do zasobów (np. do systemu I/O) w zależności od różnych własności kodu (np. miejsca, z którego program się wykonuje).

IronPython – rozszerzanie z użyciem platformy .NET

Na początek zajmijmy się stworzeniem prostego komponentu w języku C#. Poniższy kawałek kodu został stworzony z użyciem szablonu Class Library, umożliwiającego stworzenie reużywalnego podzespołu (assembly). Poniższy kod zawiera definicję prostej klasy. W wyniku jego kompilacji powstanie plik z rozszerzeniem .dll, będący podzespołem w zarządzanym kodzie pośrednim IL (Intermediary Language), który będzie mógł zostać wykonany przez środowisko uruchomieniowe .NET Runtime.

using System;

namespace CSharpLib
{
    public class SampleClass
    {
        public string SayHello(string name)
        {
            return String.Format("Hello, {0}!", name);
        }
    }
}

W następnym kroku spróbujemy użyć stworzonej przed chwilą biblioteki z poziomu języka IronPython. Jak zauważymy na poniższym przykładzie, nie stanowi to najmniejszej trudności i jest całkowicie naturalne.

#import modułu języka IronPython, odpowiedzialny za integrację z środowiskiem CLR
import clr
# dodanie refernecji do biblioteki stworzonej w języku C#
clr.AddReference("CSharpLib.dll")
# zaimportowanie konkretnej klasy
from CSharpLib import SampleClass
# dodanie referencji do standardowej biblioteki System.Xml.dll
clr.AddReference("System.Xml");
# import wszystkich klas
from System.Xml import *

# Przykład wykorzystania własnej klasy SampleClass
sc = SampleClass()
print sc.SayHello("Bartek")

# Przykład wykorzystania klasy XmlDocument pochodzącej z biblioteki System.Xml
xml = XmlDocument()
xml.Load("http://sxp.microsoft.com/feeds/3.0/msdntn/patterns-and-practices-Announcements");
print xml.DocumentElement.InnerText

IronPython – prosta aplikacja Windows Forms

Nawet w dobie zaawansowanych, sterowanych dotykowo interfejsów użytkownika duża część aplikacji może z powodzeniem wykorzystywać technologię do budowy „tradycyjnych” okienkowych interfejsów użytkownika, czyli Windows Forms.

Niniejszy podpunkt nie będzie obszernym wprowadzeniem do tej technologii, a jedynie ilustracją wykorzystania języka Python do budowy prostych aplikacji z interfejsem użytkownika. Osoby zainteresowane technologią Windows Forms powinny sięgnąć do jednej z wielu dostępnych książek lub samouczków dostępnych w Internecie.

Osoby zainteresowane tworzeniem aplikacji typu „gruby klient” – z użyciem technologii firmy Microsoft, czyli Windows Forms lub Windows Presentation Foundation – powinny odwiedzić stronę dostępną pod adresem: https://windowsclient.net. Natomiast przygodę z technologią Windows Forms można rozpocząć od wpisania następującego adresu: https://msdn.microsoft.com/en-us/library/dd30h2yb.aspx – gdzie znajduje się bardzo obszerna dokumentacja oraz setki przykładów.

Przejdźmy zatem do pierwszej, prostej aplikacji Windows Forms (która jest prostym czytnikiem RSS), analizując poniższy kod:

# import niezbędnych bibliotek
import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Xml')
clr.AddReference('System.Net')
clr.AddReference('System')

from System.Windows.Forms import *
from System.Xml import *
from System.Net import *
from System import *

# procedura, która będzie wykonywana po naciśnięciu przycisku na formatce
# realizuje „główną funkcjonalność” aplikacji
# realizacja przy pomocy klas ze standardowych bibliotek .NET
def GetRssTitles(sender, event):
    rssUrl = form.GetRssUrl()
    request = WebRequest.Create(rssUrl)
    response = request.GetResponse()
    responseStream = response.GetResponseStream();
    reader = XmlTextReader(responseStream);
    
    while reader.Read():
        if reader.Name == 'item':
            while reader.Read():
                if reader.Name == 'title':
                   form.AddRssTitle(reader.ReadString())

# klasa enkapsulująca główną formatkę w naszej aplikacji
class MyForm(Form):       
    def __init__(self):
        self.Width = 500
        
#deklaracja oraz ustawienie właściwości poszczególnych kontrolek
        textbox = TextBox()
        textbox.Top = 5
        textbox.Left = 5
        textbox.Width = 490     
        button = Button()
        button.Left = 5
        button.Top = 30
        button.Text = 'Get feeds'
        button.Click += GetRssTitles
        
        listbox = ListBox()
        listbox.Left = 5
        listbox.Top = 58
        listbox.Width = 490
        listbox.Height = 300
        
        self.textbox = textbox
        self.listbox = listbox
        
        self.Controls.Add(textbox)
        self.Controls.Add(button)
        self.Controls.Add(listbox)
        
    def GetRssUrl(self):
        return self.textbox.Text
    
    def AddRssTitle(self, title):
        self.listbox.Items.Add(title)

# zainstancjonowanie obiektu typu formatka
form = MyForm()
Application.Run(form)

A oto wynik działania naszej aplikacji:

**Rys.2. Aplikacja Windows Forms.

IronPython – aplikacja Windows Presentation Foundation

W przypadku programowania w języku IronPython możemy również korzystać z nieco nowocześniejszych technologii oferowanych przez platformę .NET Framework. Tym razem skorzystamy również z zalet, jakie daje w procesie projektowania interfejsów użytkownika środowisko programistyczne Visual Studio – stworzymy aplikację w technologii WPF. Zainteresowanych pełnymi możliwościami technologii Windows Presentation Foundation odsyłam do dokumentacji MSDN: https://msdn.microsoft.com/en-us/library/ms754130.aspx.

Technologia WPF pozwala między innymi na rozdzielenie warstwy prezentacji oraz kodu do osobnych plików. Opis interfejsu użytkownika może znajdować się w osobnym pliku w języku XAML, a do jego stworzenia możemy wykorzystać zarówno wbudowany w Visual Studio edytor, jak i specjalistyczne aplikacje typu Microsoft Blend.

**Rys.3.Projekt aplikacji WPF dla języka IronPython w Visual Studio 2010.

**Rys.4.  Wsparcie dla tworzenia interfejsów w technologii WPF.

Poniżej kod reprezentujący interfejs użytkownika, opisany przy użyciu języka XAML:

<Window 
       xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
       Title="IronPythonWpfApplication" Height="400" Width="600"> 
       <Grid Height="385" Width="595">
        <Button Content="Get Rss Titles" Height="23" HorizontalAlignment="Left" Margin="12,41,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" VerticalAlignment="Top" Width="566" Name="textbox" />
        <Expander Height="288" HorizontalAlignment="Left" Margin="14,74,0,0" VerticalAlignment="Top" Width="565">
            <Grid>
                <ListBox Height="253" HorizontalAlignment="Left" Margin="6,6,0,0" VerticalAlignment="Top" Width="551" Name="listbox" />
            </Grid>
        </Expander>
    </Grid>
</Window>

Kod aplikacji w języku IronPython przedstawia się następująco:

import wpf
import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Xml')
clr.AddReference('System.Net')
clr.AddReference('System')

from System.Windows import Application, Window
from System.Xml import *
from System.Net import *
from System import *

class MyWindow(Window):
    def __init__(self):
        wpf.LoadComponent(self, 'IronPythonWpfApplication.xaml')
    
    def Button_Click(self, sender, e):
        rssUrl = self.textbox.Text
        request = WebRequest.Create(rssUrl)
        response = request.GetResponse()
        responseStream = response.GetResponseStream();
        reader = XmlTextReader(responseStream);
    
        while reader.Read():
            if reader.Name == 'item':
                while reader.Read():
                    if reader.Name == 'title':
                        self.listbox.Items.Add(reader.ReadString())

if __name__ == '__main__':
    Application().Run(MyWindow())

Wynik wykonania kodu:

**Rys.5.Aplikacja WPF w IronPython.

IronPython – hostowanie we własnych aplikacjach

Specjalne API dostarczane wraz z częścią platformy .NET odpowiedzialną za wykonywanie dynamicznych języków programowania, czyli DLR (Dynamic Language Runtime), umożliwia hostowanie języków skryptowych we własnych aplikacjach. IronPython posiada dodatkowo wiele własnych mechanizmów i rozszerzeń pozwalających na łatwe wykorzystanie tego języka w różnych, nawet bardzo zaawansowanych scenariuszach.

Jaki jest najbardziej powszechny przypadek użycia tego typu funkcjonalności? Otóż stosuje się ją bardzo często, gdy chcemy dostarczyć możliwość automatyzacji funkcjonalności dostarczanej przez naszą aplikacje za pomocą różnego rodzaju skryptów. Obecnie taką możliwość oferuje wiele programów – np. Microsoft Office czy produkty firmy Adobe, nie wspominając już o samym systemie operacyjnym. Zamiast jednak wymyślać własną gramatykę języka oraz tworzyć wyspecjalizowane parsery i interpretery, można wykorzystać język, który jest już na dobre zadomowiony w świecie programistów, czyli Python.

Przyjrzyjmy się, zatem najprostszemu przypadkowi wykorzystania tego typu mechanizmu. W tym celu wykorzystamy klasę o nazwie Python, dostępną w bibliotece IronPython.dll. Biblioteka ta jest dostępna standardowo, po zainstalowaniu paczki instalacyjnej z językiem IronPython.

Poniższy kod ilustruje, jak łatwo można wykonać kod w języku IronPython z poziomu własnych aplikacji:

using IronPython.Hosting;

namespace PythonHostingSamples
{
    class Program
    {
        static void Main(string[] args)
        {
            var engine = Python.CreateEngine();
            engine.CreateScriptSourceFromString("print 'hello world'").Execute();

        }
    }
}

W kolejnym, nieco bardziej zaawansowanym przykładzie widzimy, jak wykorzystać zdefiniowaną w kodzie Pythona własną funkcję oraz klasę:

using IronPython.Hosting;
using System;

namespace PythonHostingSamples
{
    class Program
    {
        static void Main(string[] args)
        {
            var engine = Python.CreateEngine();
            var scope = engine.CreateScope();
            var source = engine.CreateScriptSourceFromString(
                "def adder(arg1, arg2):\n" +
                "   return arg1 + arg2\n" +
                "\n" +
                "class MyClass(object):\n" +
                "   def __init__(self, value):\n" +
                "       self.value = value\n");
            source.Execute(scope);

            var adder = scope.GetVariable<Func<object, object, object>>("adder");
            Console.WriteLine(adder(2, 2));
            Console.WriteLine(adder(2.0, 2.5));

            var myClass = scope.GetVariable<Func<object, object>>("MyClass");
            var myInstance = myClass("hello");

            Console.WriteLine(engine.Operations.GetMember(myInstance, "value"));
        }
    }
}

Powyższe przykłady pokazują nam jak łatwo można wykonywać kod w języku IronPython we własnych aplikacjach. Jeżeli więc chcemy udostępniać do zewnętrznej automatyzacji model obiektowy naszej aplikacji, to właśnie zobaczyliśmy jeden z prostszych sposobów.

Podsumowanie

W niniejszym artykule omówiliśmy integrację języka IronPython z platformą .NET i na czym ona polega. Stworzyliśmy proste aplikacje w technologiach Windows Forms oraz WPF. Zobaczyliśmy również przykład rozszerzania możliwości języka przy użyciu własnego kodu oraz sposoby hostowania języka Python we własnych aplikacjach.

W kolejnym artykule zajmiemy się wykorzystaniem języka IronPython w technologii do budowy aplikacji RIA (Rich Internet Application), czyli Silverlight.