2007.02_.NET + Python = IronPython_[Programowanie .N].pdf

(274 KB) Pobierz
441714710 UNPDF
Programowanie
.NET
Janusz Gołdasz
Iwona Gołdasz
.NET + Python = IronPython
thona na platformie .NET? Z jakich mecha-
nizmów (narzędziach) dostępnych w świecie
.NET może programista Pythona skorzystać? Odpo-
wiedź jest jedna: możliwość wyboru. Wybór języka pro-
gramowania sprowadza się często do indywidualnych
preferencji i cech/typu projektu, nad którym pracujemy.
Python w przedstawianej implementacji jest inte-
resującym rozwiązaniem na platformy .NET i Mono
(fanom Javy polecamy Jythona) i wydaje się, iż ma
wszelkie dane ku temu, aby przyciągnąć do siebie
nowych zwolenników. Skryptowy Python, stworzony
we wczesnych latach 90-tych przez Guido van Rosu-
uma, jest dziś wykorzystywany praktycznie na każ-
dej powszechnej platformie ( Windows, Max, Lunux/
Unix ) od komputerów stacjonarnych po palmtopy i te-
lefony komórkowe ( Nokia ) w takich dziedzinach jak,
wizualizacja i gry, networking, aplikacje webowe, de-
sktopowe, inżynieryjne, bazy danych, etc. Jest uży-
wany do tworzenia prostych skryptów, jak i dużych
aplikacji ( Zope, Plone ). Poniżej postaramy się przed-
stawić jego implementację na platformę .NET.
Rysunek 1. Odtworzony dokument XML
gnięcia IronPythona do grafi ki 3D na przykładzie biblio-
teki Irrlicht .NET 3D. Zakładamy opanowanie przez czy-
telnika podstaw programowania w Pythonie i .NET. Ko-
niecznie trzeba zwrócić uwagę, iż IronPython i CPython
to dwie różne implementacje tego samego języka. Róż-
nic w chwili obecnej jest sporo – od bardzo trywialnych,
które sprowadzają się do wyświetlania różnych komuni-
katów o błędach, po takie, które wynikają z nieobecno-
ści takiego czy innego modułu, np. cmath lub os .
Narzędzia
Standardowo, IronPython (binaria i kody źródłowe do
pobrania z CodePlex ) daje użytkownikowi zestaw po-
dobnych narzędzi programistycznych co inne imple-
mentacje tego języka ( CPython ). Do dyspozycji jest
konsola interpretera poleceń ( ipy.exe ), a uruchamianie
skryptów i poleceń IronPythona odbywa się w znanych
nam postaciach: wsadowo lub interaktywnie. W chwi-
li obecnej, jedyne środowisko programistyczne ( IDE )
pozwalające tworzyć/edytować skrypty w tym języku
to Visual Studio 2005 koniecznie w wersji Standard lub
wyższej. W chwili obecnej brak wsparcia dla IronPytho-
na w wersji Visual Studio Express, choć istnieje ono
w Web Developer Express (po zainstalowaniu dodatko-
wego pakietu integrującego IronPythona z ASP .NET).
Do tworzenia przykładów zawartych w niniejszym ar-
tykule autorzy korzystali z Visual Studio Express ( C# )
oraz popularnego IDLE ( Python ).
IronPython
Twórca IronPythona, Jim Hugunin, jest znany z wcze-
śniejszych (udanych) implementacji Pythona na maszy-
nę wirtualną Javy – Jython. Projekt na platformę .NET
powstał około roku 2003 i jest przykładem świetnej
i szybkiej implementacji dynamicznego języka skrypto-
wego w środowisku CLR ( platformy .NET i Mono ). Inte-
resujące jest oparcie się przez twórców na środowisku
CLR, co w rezultacie zapewnia wykorzystywanie biblio-
tek .NET w tworzonych skryptach, aplikacjach desktopo-
wych i webowych przy użyciu IronPythona. Co ciekawe,
przy zachowaniu pewnych reguł, możliwe jest korzysta-
nie ze standardowych bibliotek CPythona celem zwięk-
szania funkcjonalności tworzonej aplikacji o potrzebne
elementy. Współpracę IronPythona z .NET pokażemy
na kilku wybranych przykładach. Zaczniemy od napisa-
nia skryptu w Pythonie w rodzaju prostej przeglądarki pli-
ków XML z wykorzystaniem kontrolki TreeView i formula-
rza Form . Tworzenie nowych rozszerzeń ( klas ) w C# dla
IronPythona pokażemy na przykładzie podobnej aplika-
cji, gdzie komponent przeglądarki osadzimy tym razem
w wyświetlanym formularzu. Korzystanie z interprete-
ra IronPythona przedstawimy na przykładzie aplikacji –
słownika. Na koniec, omówimy prosty przykład zaprzę-
Skrypty
Omówienie IronPythona rozpoczniemy od skryptu, któ-
rego działanie polegać ma na odczytaniu pliku XML,
a następnie odtworzeniu jego struktury w kontrolce
TreeView jak na Rysunku 1. Treść skryptu przedstawio-
no w Listingu 1. Rozpoczynamy od zapewnienia sobie
dostępu do standardowych modułów CPythona. Robi-
my to przez umieszczenie na początku skryptu nastę-
pujących wierszy
Autorzy są entuzjastami Pythona we wszystkich wcie-
leniach (czytaj: implementacjach).
Kontakt: ijmj.goldasz@gmail.com
import sys
sys.path.append(r"c:\python24\lib")
30
www.sdjournal.org
Software Developer’s Journal 02/2007
D laczego ktoś mógłby chcieć korzystać z Py-
441714710.012.png 441714710.013.png 441714710.014.png 441714710.015.png 441714710.001.png 441714710.002.png 441714710.003.png 441714710.004.png
.NET + Python = IronPython
Oczywiście, importujemy moduł clr ( CLR ), a dostęp do potrzeb-
nych modułów .NET zapewniamy sobie dzięki metodzie clr.Ad-
dReferenceByPartialName(...) . W naszym skrypcie utworzy-
my 2 klasy – pierwszą o nazwie xmlTree dziedziczącej po kla-
sie TreeView , drugą zaś (dziedziczącą po klasie Form) nazwie-
my HelloXML . Klasa xmlTree posiada 2 zmienne: pathToXML
(w której przechowywać będziemy ścieżkę do analizowanego pli-
ku) oraz root , która posłużymy się do przechowania treści doku-
mentu ( XmlDocument ). Odtworzenie struktury dokumentu XML
najłatwiej rozwiązać rekurencyjnie – stąd obecność w ciele kla-
sy kolejnych metod. Pierwsza z nich o nazwie AddNode(...) po-
rusza się rekurencyjnie po strukturze (drzewiastej) analizowane-
go dokumentu, dodając odwiedzane węzły inXMLNode do kolej-
nych węzłów inTreeNode naszej kontrolki. Druga metoda Popula-
teTree() to sterownik wczytujący żądany dokument do zmiennej
root i wywołujący rekurencyjną metodę AddNode(...) . Na tym za-
danie odtworzenia struktury dokumentu XML się kończy. Chcąc
umieścić (wyświetlić) naszą kontrolkę w formularzu, w konstruk-
torze klasy HelloXML tworzymy instancję klasy xmlTree i wywołu-
jemy metodę PopulateTree() , Teraz wystarczy tylko dodać ją do
formularza i w funkcji Main umieścić znaną skądinąd
Application.Run(HelloXML(nazwa_pliku_XML))
i efekt jest widoczny jak przedstawionej ilustracji w Rysunku 1.
Chcąc sprowokować pojawienie się wyjątku, wywołamy skrypt
z nazwą nieistniejącego dokumentu – zob. Rysunek 2.
Twor zenie rozszer zeń
Tworzenie rozszerzeń .NET dla IronPythona pokażemy na iden-
tycznym przykładzie jak poprzednio – zob. Listing 2. Nasze za-
danie polega na osiągnięciu identycznej funkcjonalności jak
Listing 1. Pierwszy przykład - xmlTree
import sys
# Dodajemy dostep do standardowych modulow Pythona
sys . path . append ( r "c: \p ython24 \l ib" )
# Importujemy Common Language Runtime …
import clr
# Formularze, kontrolki
clr . AddReferenceByPartialName ( "System.Windows.Forms" )
clr . AddReferenceByPartialName ( "System.Drawing" )
# XML
clr . AddReferenceByPartialName ( "System.Xml" )
# ...oraz inne potrzebne moduły
import System
from System . Windows . Forms import *
from System . Drawing import *
from System . Xml import *
# Tworzymy kontrolke przegladarki
# – dziedziczy po klasie TreeView
class xmlTree ( TreeView ):
def __init__ ( self ): # Domyslny bezparametrowy konstruktor
self . Nodes . Clear ()
self . pathToXml = '' # Sciezka do pliku XML
self . root = None
# W metodzie PopulateTree generujemy structure pliku XML
def PopulateTree ( self ):
self . root = XmlDocument () # korzen
try : # obsluga wyjatkow
self . root . Load ( self . pathToXml ) # Otwieramy plik
# Kasujemy wszystkie istniejace wezly
self . Nodes . Clear ()
# Dodajemy pierwszy wezel (korzen) do drzewa
self . Nodes . Add ( TreeNode ( self . root .
DocumentElement . Name ))
tNode = TreeNode ()
tNode = self . Nodes [ 0 ] # Wskazanie na korzen
# i rekurencyjnie zapelniamy cale drzewo
self . AddNode ( self . root . DocumentElement , tNode )
except Exception , detail :
# Komunikujemy blad
MessageBox . Show ( System . Convert . ToString ( detail ))
self . Nodes . Clear ()
self . Nodes . Add ( TreeNode ( System . Convert . ToString (
detail )))
# Zadaniem rekurencyjnej metody AddNode jest dodawanie
# kolejnych wezlow do kontrolki
def AddNode ( self , inXmlNode , inTreeNode ):
tNode = TreeNode ()
i = 0
# Gdy rodzic inXmlNode posiada dzieci,
# to rekurencyjnie wedrujemy po drzewku
if ( inXmlNode . HasChildNodes ):
for node in inXmlNode . ChildNodes :
xNode = inXmlNode . ChildNodes [ i ]
inTreeNode . Nodes . Add ( TreeNode ( xNode . Name ))
tNode = inTreeNode . Nodes [ i ]
self . AddNode ( xNode , tNode )
i += 1
else :
inTreeNode . Text =( inXmlNode . OuterXml )
# Klasa HelloXML dziedziczy po klasie Form
class HelloXML ( Form ):
# Konstruktor z parametrem w postaci nazwy pliku XML
def __init__ ( self , filename ):
self . xmlTree = xmlTree () # Instancja klasy xmlTree !
self . xmlTree . pathToXml = filename
# Zapelniamy drzewko kontrolki …
self . xmlTree . PopulateTree ()
self . xmlTree . Dock = DockStyle . Fill
# … i dodajemy je do formularza
self . Controls . Add ( self . xmlTree )
self . Size = Size ( 300,200 )
self . AutoSizeMode = AutoSizeMode . GrowAndShrink
# Tu metoda Main jest na zewnatrz klasy
def Main ( filename ):
Application . Run ( HelloXML ( filename ))
# Na koniec: uruchamiamy skrypt z parametrem z postaci pliku
# XML i wywolujemy metode Main
if __name__ == "__main__" :
import sys
Main ( sys . argv [ 1 ])
Software Developer’s Journal 02/2007
www.sdjournal.org
31
441714710.005.png
Programowanie
.NET
w poprzednim przykładzie. Tym razem jednak, rozpoczniemy
od utworzenia kontrolki przeglądarki i wywołania jej w nowym
skrypcie. Zaczynamy od utworzenia nowego projektu typu Class
Library w Visual Studio i utworzenia nowej klasy o nazwie (nie-
spodzianka!) xmlTree . Oczywiście, klasa ta powinna dziedziczyć
po klasie TreeView . W ciele klasy pojawiają się konstruktor z pa-
rametrem w postaci nazwy pliku XML, którego strukturę odtwa-
rzamy oraz prywatne metody o znanej już funkcjonalności i na-
zwach: PopulateTree() i AddNode(XmlNode, TreeNode) . Zmienna
m_directoryPath posłuży nam do przechowywania nazwy od-
twarzanego pliku. Dodatkowo, ciało klasy uzupełnimy o nową
publiczną właściwość o nazwie newFile . Pozwoli ona nam za-
równo na odczyt nazwy analizowanego pliku, jak i odtworzenie
struktury pliku XML (pośrednio, poprzez wywołanie w treści wła-
ściwości metody PopulateTree() ) .
Tak utworzoną kontrolkę możemy bezproblemowo użyć
w naszym skrypcie, co przedstawia Listing 3. Oprócz oma-
wianej już zawartości w skrypcie pojawia się referencja do
nowej kontrolki przy użyciu metody AddReferenceToFi-
le modułu clr. i import klasy xmlTree do naszego skryptu.
W tym przypadku zaczynamy od utworzenia nowej klasy
o nazwie xmlViewer dziedziczącej po klasie Form . W kon-
struktorze tworzymy instancję kontrolki self.xmTree i odtwa-
rzamy strukturę pliku XML. Teraz, wystarczy tylko dodać
kontrolkę do formularza i po jego wywołaniu uzyskujemy
identyczny efekt, jak w poprzednim przypadku.
Listing 2. Kontrolka xmlTree – C#
using System . Collections ;
using System . ComponentModel ;
using System . Drawing ;
using System . Windows . Forms ;
using System . Xml ;
// Dziedziczymy do klasie TreeView
public class xmlTree : System . Windows . Forms . TreeView {
// skladowe klasy sciezka do pliku XML (z nazwa)
private string m_directoryPath ;
// Bezparametrowy konstruktor
public xmlTree () { InitializeComponent (); }
// Przeciazony konstruktor z parametrem w postaci nazwy
// pliku XML
public xmlTree ( string file ) {
InitializeComponent (); // Inicjalizacja komponentu
m_directoryPath = file ;
// Odtworzenie struktury pliku XML w kontrolce
PopulateTree ();
}
// Obsluga wyjatkow
catch ( XmlException xmlEx ) {
MessageBox . Show ( xmlEx . Message );
}
catch ( Exception ex ) {
MessageBox . Show ( ex . Message );
}
}
// Rekurencyjna metoda kopiujaca strukture dokumentu
private void AddNode ( XmlNode inXmlNode ,
TreeNode inTreeNode ) {
XmlNode xNode ; // wezel DOM
TreeNode tNode ; // wezel TreeNode
XmlNodeList nodeList ; // lista wezlow DOM
int i ;
// Wedrowka po wezlach DOM do czasu napotkania
// “bezdzietnego” wezla
if ( inXmlNode . HasChildNodes ) {
nodeList = inXmlNode . ChildNodes ;
for ( i = 0 ; i <= nodeList . Count - 1 ; i ++) {
xNode = inXmlNode . ChildNodes [ i ];
inTreeNode . Nodes . Add ( new TreeNode ( xNode . Name ));
tNode = inTreeNode . Nodes [ i ];
AddNode ( xNode , tNode ); // Rekurencja…
}
protected override void Dispose ( bool disposing ) {
if ( disposing ) {
if ( components != null )
components . Dispose ();
}
base . Dispose ( disposing );
}
private void InitializeComponent () {
// Inicjalizacja konstrolki
}
} else {
inTreeNode . Text =( inXmlNode . OuterXml ) . Trim ();
}
// Odtwarzanie struktury pliku XML
private void PopulateTree () {
try {
XmlDocument dom = new XmlDocument ();
dom . Load ( m_directoryPath ); // Pobranie pliku
this . Nodes . Clear ();
// Tworzymy korzen
this . Nodes . Add ( new TreeNode ( dom . DocumentElement .
Name ));
TreeNode tNode = new TreeNode ();
tNode = this . Nodes [ 0 ];
// Rekurencyjnie wypelniamy kontrolke wezlami
// XmlNode
AddNode ( dom . DocumentElement , tNode );
}
}
// new File zwraca nazwe dokumentu, ew. wyswietla/
// generuje strukture nowego pliku
public XmlDocument newFile {
get {
return directoryPath ;
}
set {
m_directoryPath = value ;
PopulateTree ();
}
}
}
32
www.sdjournal.org
Software Developer’s Journal 02/2007
441714710.006.png
.NET + Python = IronPython
Rysunek 4. Irrlicht .NET
Rysunek 2. IronPython w Visual Studio – Solution Explorer
dyfi kowany już słownik i wyświetlić go w kontrolce listy lvItems
naszego formularza jak na Rysunku 4.
Sam skrypt odczytujący słownik przedstawiony jest w Listin-
gu 5. Jego treść nie odbiega wiele od tych, które widzieliśmy do
tej pory. Oprócz znanych nam konstrukcji potrzebne są nam jesz-
cze typy ogólne (słownik), które importujemy instrukcją
Hosting
Bardzo często przy projektowaniu aplikacji mamy do czynienia
z potrzebą zwiększania funkcjonalności aplikacji czy automaty-
zacji określonych działań przy użyciu zewnętrznych skryptów
(w dowolnym języku). Konieczny jest mechanizm interprete-
ra udostępniającego określony interface aplikacji na zewnątrz w
treści skryptu i umożliwiający pobranie wyniku działania skryptu
z powrotem do otoczenia, z którego dane zostały wysłane. Dzia-
łanie interpretera poleceń IronPythona zilustrujemy na przykła-
dzie prostej aplikacji wczytującej zewnętrzny słownik (przy uży-
ciu zewnętrznego skryptu .py ) i wyświetlającej nowe dane w kon-
trolce listy ( ListView ). Takie podejście pozwala w naturalny spo-
sób oddzielić logikę biznesową aplikacji od warstwy prezentacyj-
nej. Kod aplikacji przedstawiono w Listingu 4. Rozpoczynamy od
utworzenia nowego projektu typu Windows Application w Visu-
al Studio o przykładowej nazwie frmAppHost . Aby nasza aplika-
cja była w stanie interpretować wyniki działania wczytywanego
skryptu, do projektu dodajemy referencje do nowych modułów:
IronPython.Modules i IronPython.Hosting – zob. Rysunek 2. Na-
sza aplikacja jest prostym słownikiem, więc na początek dekla-
rujemy zmienną dictionary klasy Dictionary<int,string> służącą
przechowywaniu wczytywanych słów. W dalszej kolejności two-
rzymy interpreter Pythona o nazwie engine i przekierowujemy
standardowe we/wy interpretera do nowego pliku instrukcjami
from System.Collections.Generic import *
a sam słownik inicjujemy następująco
dict = Dictionary[Int32,String]()
Listing 3. Przykład użycia kontrolki - Python
import sys # Dostep do standardowych modulow Pythona
sys . path . append ( r "c: \p ython24 \l ib" )
# Tradycyjnie, importujemy CLR i potrzebne biblioteki .NET
import clr
clr . AddReferenceByPartialName ( "System.Windows.Forms" )
clr . AddReferenceByPartialName ( "System.Drawing" )
from System . Windows . Forms import *
# Tworzymy referencje do utworzonej kontrolki przegladarki
clr . AddReferenceToFile ( "xmltree.dll" ) # Import kontrolki
import xmlTree
# Klasa xmlViewer to formularz – dziedziczy po klasie Form
class xmlViewer ( Form ):
# Tworzymy kontruktor z parametrem w postaci nazwy
# analizowanego pliku
def __init__ ( self , fi lename ):
# Tworzymy instancje kontrolki i odtwarzamy structure
# pliku XML
self . xmlTree = xmlTree ()
self . xmlTree . newFile = fi lename
# Dodajemy kontrolke przegladarki do formularza
self . Controls . Add ( self . xmlTree )
# …i ustawiamy parametry formularza
self . AutoSize = True
self . AutoSizeMode = AutoSizeMode . GrowAndShrink
# Identycznie jak poprzednio - Metoda Main
def Main ( fi lename ):
Application . Run ( xmlViewer ( fi lename ))
if __name__ == "__main__" :
import sys
Main ( sys . argv [ 1 ])
engine.SetStandardOutput(FileStreamObject);
engine.SetStandardError(FileStreamObject);
Potrzebny nam jeszcze nowy moduł em oraz słownik locals
do przechowywania eksportowanych zmiennych (słownika –
words (dictionary), nazwy pliku słownika – myDictionaryFile ).
Teraz wystarczy wystarczy wykonać skrypt instrukcją engine.
ExecuteFile("getDictionary.py", em, locals); aby odczytać zmo-
Rysunek 3. Słownik
Software Developer’s Journal 02/2007
www.sdjournal.org
33
441714710.007.png 441714710.008.png 441714710.009.png 441714710.010.png
Programowanie
.NET
Zwróćmy uwagę na sposób deklaracji typów ogólnych w IronPy-
thonie. Działanie skryptu rozpoczynamy od sprawdzenia obec-
ności słownika myDictionaryFile , aby w dalszej kolejności przejść
do sekwencyjnego odczytu pliku i zapisu słów do słownika.
Zwróćmy uwagę, że końcowe komunikaty pojawią się w żąda-
nym logu application-log.txt .
W Sieci
http://www.python.org
http://irrlicht.sourceforge.net
http://www.jython.org
http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronP
ython
http://www.asp.net/ironpython
Zastosowanie: Grafi ka 3D
W aspekcie użycia IronPythona w rzeczywistych projektach, po-
wstaje oczywiste pytanie, jak wygląda współpraca IronPythona
Listing 4. Użycie interpretera poleceń Pythona – C#
z innymi bibliotekami. Okazuje się, że całkiem nieźle. Do demon-
stracji w naszym przypadku posłużyliśmy się w znanym środowi-
skiem grafi cznym Irrlicht w wersji .NET. Napiszemy skrypt przed-
stawiony w Listingu 6. wyświetlający teksturowaną siatkę tere-
nu. Jak zwykle, importujemy moduły clr i System , a referencję do
środowiska 3D tworzymy przy użyciu konstrukcji AddReference-
ToFile(...) . W rezultacie, możemy tu już zaimportować samo śro-
dowisko i potrzebne nam biblioteki ( Video , Core , Scene , GUI ).
Scenę skonfi gurujemy w konstruktorze klasy IrrlichtExample .
W konstruktorze tworzymy instancję bazowej klasy IrrlichtDevice
self.device . sterownik video self.driver , kamerę self.camera oraz
...
using IronPython . Hosting ;
using IronPython . Modules ;
...
private void frmAppHost_Load ( object sender , EventArgs e ) {
try {
// Tworzymy slownik do przechowywania pobieranych slow
Dictionary < int , string > dictionary =
new Dictionary < int , string >();
// Interpreter Pythona
PythonEngine engine = new PythonEngine ();
// W jezyku Pythona: os.path.join(“…”)
engine . AddToPath ( Application . StartupPath );
// Nowy log aplikacji – zamiast konsoli
System . IO . FileStream fs = new System . IO . FileStream (
"application-log.txt" , System . IO . FileMode . Create );
// Przekierowujemy standardowe we/wy do nowego pliku
engine . SetStandardOutput ( fs );
engine . SetStandardError ( fs );
// Tworzymy nowy modul i slownik
EngineModule em = engine . CreateModule ();
Dictionary < string , Object > locals =
new Dictionary < string , object >();
locals . Add ( "words" , dictionary );
locals . Add ( "myDictionaryFile" , "dictionary.txt" );
engine . ExecuteFile ( "getDictionary.py" , em , locals );
engine . Shutdown ();
// Odczytujemy z powrotem liste
dictionary =( Dictionary < int , string >) locals [ "words" ];
// Na koniec wypelniamy slownikiem liste
foreach ( KeyValuePair < int , string > item in
dictionary ) {
ListViewItem lvItem = new ListViewItem (
item . Key . ToString ());
lvItem . SubItems . Add ( item . Value . Trim ());
lvItems . Items . Add ( lvItem );
Listing 5. Użycie interpretera poleceń Pythona – skrypt
# Jak we wszystkich przypadkach – import modulow i bibliotek
import sys
sys . path . append ( r "c: \p ython24 \l ib" )
import string
import os
# Import .NET
import clr
from System import *
from System . Collections . Generic import *
dict = Dictionary [ Int32 , String ]()
# Na poczatek, sprawdzamy istnienie slownika
if os . path . exists ( myDictionaryFile ):
f = open ( filename ,'r' ) # Otwarcie pliku
str = _
count = 0 ; # licznik slow
while str !=:
try :
line = f . readline () # Odczyt wiersz po wierszu
if line != '' :
# Dzielimy wiersz na czesci
( index , word )= line . split ( r "," )
# … i dodajemy do slownika
dict . Add ( Int32 ( index ) , String ( word ));
count = count + 1 # Zliczamy pozycje
except IOError , ( errno , strno ):
# Obsluga wyjatku
print "%s in line %s \n " , errno , strno
f . close ()
if ( count > 1 ):
# Uwaga: Wszystkie komunikaty pojawia sie w logu
print ' Loaded data from file -> ', filename
print ' There are items -> ', count
for item in words :
print item . Key , ":" , item . Value
words = dict # koniec!
}
}
catch ( IronPython . Runtime . Exceptions .
PythonNameErrorException E ) {
MessageBox . Show ( E . Message );
}
catch ( Exception E ) {
MessageBox . Show ( E . Message );
}
}
34
www.sdjournal.org
Software Developer’s Journal 02/2007
441714710.011.png
Zgłoś jeśli naruszono regulamin