Friday, December 26, 2008

Python - gdy Gruszka jest Pomarańczą

W tym wpisie chciałbym przybliżyć działanie metody __new__(). Jest to metoda statyczna wywoływana w trakcie tworzenia obiektu, zanim sam obiekt jeszcze powstanie. Jej zadaniem jest właśnie zwórcenie obiektu. Czyli co ? Co to dla nas oznacza ? Oznacza na przykład to iż istnieje metoda, którą mogę zaimplementować (coś w niej zrobić) wywoływana zanim jeszcze istnieje obiekt. Mogę więc wpłynąć na to jak ten obiekt będzie na prawdę tworzony i co więcej ! To ja mogę zdecydować jaki obiekt będzie stworzony i zwrócony.Tworząc obiekt jednego typu mogę zwrócić obiekt innego ? Na przykład. Możesz przekazać troszkę inną listę parametrów jego metodzie __init__ albo zainicjalizować jakieś elementy przed jego stworzeniem. Zobaczymy przykład.
class Pomarancz(object):
    pass

class Gruszka(object):

def __new__(type):
    return Pomarancz()

if __name__ == '__main__':
    gruszka = Gruszka()
    print type(gruszka)
Co tu się dzieje. Stworzyliśmy sobie dwie klasy: Pomarancz i Gruszka. Gruszka jest jakaś podejżana, ale to zaraz do tego wrócimy. Co w ramach programu ? Tworzomy obiekt gruszka klasy Gruszka. Na razie na tym się zatrzymajmy. W każdym "normalnym" języku programowania gdy tworzymy obiekt jakiejś klasy dostajemy ... tak instancję tej klasy :) Jak tworzymy obiekt klasy Samolot dostajemy samolot. Jak dostajemy obiekt klasy Dziecko dostajemy dziecko. Tak samo na codzień zachowuje się Python możemy jednak, dzięki metodzie __new__ zwrócić podczas tworzenia obiektu "coś innego".Sprawdźmy co my zwróciliśmy podczas tworzenia Gruszki. print type(gruszka) (funkcja type podaje typ obiektu, klasę obiektu który jest jej parametrem) zwróciło nam pomarańcz Pomarancz ? Wow :D To prawie jak kamień alchemiczny. Teraz zamieniamy Gruszki w Pomarańcze (to jak Ołów w Złoto).

Przyjżyjmy się metodzie __new__(). Skoro to ona ma zwracać obiekt klasy :) to znaczy, że to co zwróci nam przez return to dostaniemy przy użyciu Gruszka(). Jak byk stoi tam zwrócenie świerzo stworzonego obiektu pomarańczy :) Teraz wszystko się zgadza.

Już słyszę głosy oburzonych programistów: "przecież Python miał być czytelny. A tu takie konstrukcje ?". Z mojego skromnego punktu widzenia służą one językowi. Jak ?
Wyobraź sobie, że chciałbyś mieć klasę UlubionyOwoc, która w zależności do tego jaki użytkownik tworzy jej instancję dostaje to co lubi najbardziej. Dzięki metodzie __new__() możesz tego w prosty sposób dokonać nie tracąc przy tym na elegancji składni i prostocie kodu (po prostu tworzysz obiekt), gdzie bez takiego rozwiązania musiałbyś tworzyć jakąś metodę statyczną w stylu UlubionyOwoc.zwroc_owoc().

Teraz jeszcze kilka szczegółów. W naszym przykładzie jak tylko interpreter natrafi na instrukcję return Pomarancz() zacznie tworzyć instancję klasy Pomarańcz. Dla nas oznacza to iż zostanie wywołane Pomarancz.__new__(), które jest domyśle a po nim Pomarancz.__init__() :) Być może dla wielu z was to już jest oczywiste :] ale piszę.

A co z argumentami, które są przekazywane podczas tworzenia obiektu. Powiedzmy Gruszka(2, jasio='imie') ? Metoda w postaci
def __new__(type, *args, **kwargs)
Pytania może rodzić kwestia: "No dobrze. A jak w metodzie __new__ klasy gruszka zwrócić obiekt klasy Gruszka ? Przecież jak zapiszę Gruszka() znowu wyląduję w __new__ i zacznę kręcić się w kółko". Słuszna uwaga. Uniwersalna metoda to:
def __new__(type, *args, **kwargs):
    return object.__new__(type, *args, **kwargs)

Gdzie type oznacza typ klasy, który chcemy "stworzyć". Przy użyciu formy Gruszka() czy Pomarancz() jest on przekazywany automatycznie jednak można tworzyć obiekty również tak object.__new__(tutaj_podaj_typ, argumenty, argumenty nazwane).

Na koniec dodam tylko, że jak już nasza klasa zwróci obiekt swojego typu to wywoływana jest metoda Gruszka.__init__ z całym kompletem parametrów przekazanym do __new__ czyli przekazanym podczas tworzenia obiektu :)

I to by było na tyle. Miłej zabawy.

Python - wywoływanie obiektu

Python umożliwia potraktowanie obiektu jak funkcji, czyli ... wywołania obiektu :) Każdy z was może sam rozważyć taką potrzebę. Widząc jak łatwo obiekt może udawać inne typy (takie jak int, complex czy nawet słownik lub listę), można się zastanowić: skoro obiekt stworzony przez nas tak dobrze może udawać najróżniejsze inne obiekty - dlaczego nie miałby móc udawać funkcji ? To w sumie też obiekt. Tutaj właśnie zaczynają prześwitywać paradygmaty programowania funkcyjnego języka Python :)

A wszystko to w kilku linijkach:
class Klasa(object):

    def __call__(self):
        print "Wywolalem sie ! z wiadomoscia :)"

if __name__ == '__main__':
    obiekt = Klasa()
    obiekt()
Co wynika z powyższego kodu ? Wyposażyliśmy nasz obiekt w metodę __call__. Gdy potem próbujemy wywołać nasz obiekt, potraktować go jak funkcję (fragment obiekt()) python sprawdzi czy istnieje metoda __call__ i jeżeli tak wywoła ją. Metoda ta zachowuje się pod wieloma względami tak jak każa inna funkcja: może przyjmować parametry lub zwracać jakąś wartość :)

Thursday, December 25, 2008

Pylons - generowanie formularzy z użyciem form alchemy

W którejś z prezentacji na Matrix eXtreme II narzekałem na to, że Pylons (niestety) nie potrafi generować formularzy. Postanowiłem w końcu sprawdzić to na kanale #pylons. Co się okazało ? Na google code rezyduje sobie spokojnie :) projekt o nazwie formalchemy. Jest to biblioteka, na dzień dzisiejszy w wersji 1.1, która potrafi generować formularze dla modeli sqlalchemy :] Fantastczna wiadomosć :) Dodatkowo w dokumentacji projektu prześwitują już informacje o admin panelu co szalenie cieszy :) Życzę powodzenia i czekam na oficjalne wieści z PylonsHQ :P

Walt Disney - mistrzostwo w antropomorfizacji

Wczoraj miałem okazję obejrzeć w telewizji bajkę "Auta", o czerwonej wyścigówce :) Film szalenie mi się podobał, naprawdę dobrze się bawiłem oglądając go. Największe wrażenie zrobił na mnie świetny polski dubbing, byłem naprawdę dumny z naszych polskich aktorów.

Równocześnie przypomniał mi się film WALL.E. Czy Wy też zauważyliście, że Walt Disney, jakby, że im przestaje wystarczać robienie zwykłych bajek, filmów, ale że celowo sobie "utrudniają". Utrudniają obierając za cel postaci zupełnie nieożywione i jakby ambicjonalnie mówili "teraz my ... tak je ożywimy, że to będzie musiało być coś niesamowitego". Auta były naprawdę dobre, ale kto oglądał WALL.Ego pamięta, że tam ... tam to było już mistrzostwo. Te roboty praktycznie nic nie mówiły, kwestie wygłaszali przedewszystkim ludzie - a ... ta cała mimika, zachowanie, czytelność gestów i ich przesłanie ... to wszystko było robione po mistrzowsku. Film o robotach, które były tak ludzkie ... coś niemożliwego.

Zastanawiam się czym jeszcze zaskoczy nas Disney. Może teraz będzie film o kamieniach, którym rzucą nas na kolana ;) Nie wiem, ale cele jakie sobie wyznaczają to dla mnie z góry nudne filmy, z których robią hity. Tylko tak dalej !

Tuesday, December 23, 2008

Python - przeciążanie operatorów z punktu widzenia programisty C++

Cała prostota przeciążąnia operatorów w Pythonie względem C++ wynika z podanych już wcześniej zalet definiowania funkcji. Przeciążenie jakiegoś operatora w tworzonej przez nas klasie polega wyłącznie odnalezieniu nazwy funkcji za nią odpowiedzialnej, wymyśleniu jak ma działać dla naszego obiektu i zaimplementowaniu jej w naszej klasie. Z puli operatorów opisanych w dokumentacji języka PythonWeźmy na przykład operator dodawania +. Jak widzimy wystarczy w naszej klasie zdefiniować dwuargumentową metodę o nazwie __add__ i nasza klasa będzie rozumiała dodawanie. Załóżmy, że będzie to zawsze suma elementów modulo 5 (pierścień modulo pięć - dla osób pamiętających jeszcze coś z matematyki dyskretnej lub algebry liniowej).

Klasa będzie musiała przetrzymywać w sobie wartość liczby. Będziemy ją zapisywać do __value. Dodatkowo aby ułatwić sobie obliczenia nauczymy naszą klasę "konwertować się do inta" :) Bo przecież bądź co bądź chodzi o obliczenia na liczbach. 


class Mod5(object):

    def __init__(self, value):
        self.__value = value

    def __int__(self):
        return self.__value

    def __add__(self, b):
        return ((int(self) + int(b)) % 5)

if __name__ == '__main__':
    a = Mod5(5)
    b = Mod5(7)
    print a + b

Metoda __init__ pobiera jeden argument, liczbę którą jest nasz obiekt. Oczywiście nie sprawdzamy mnóstwa różnych rzeczy. czy liczba jest w naszym zakresie, czy to na pewno liczba całkowita itd... Metoda __int__ wywoła się w momencie, w którym nasz obiekt będzie konwertowany na int.  Wykorzystujemy to w metodzie __add__. Jako pierwszy argument przyjmuje samego "siebie" oraz drugi obiekt ten po symbolu "+". Konwertujemy obia te obiekty (siebie i ten drugi) na inta. Otrzymujemy więc nie obiekt klasy Mod5, ale liczbę :) dodajemy je i robimy modulo 5. Linijki poniżej to już tylko test - czy działa :)

Jak widać przeładowywanie operatorów, czy nawet modelowanie klasy, która będzie miałą możliwość rzutowania na najróżniejsze inne typy (naprawdę tutaj są ogromne możliwości, może być rzutowana na complex, long nawet na listę czy krotkę), wszystko to jest banalnie proste i łatwe :) Wystarczy zajrzeć do odpowiednigo działu dokumentacji Pythona :) i 

Monday, December 22, 2008

Python - polimorfizm z punktu widzenia programisty C++

Właściwie temat był już poruszany w wątku, w którym napisałem kilka słów o wyłapywaniu wyjątków.

Ponieważ zarówno w przypadku metod jak i funkcji nie trzeba definiować typu obiektów, które są do nich przekazywane wszystkie metody zachowują się tak jakby były wirtualne. Choć ciężko o tym mówić przy braku deklaracji typu parametru - po prostu są wywoływane na obiekcie przekazanym do funkcji czy metody jaki by ten obiekt nie był. Tak zwany polimorfizm najlepiej zobaczyć we wspomnianym już powyżej przykładzie wyłapywania wyjątków. Wyłapując wyjątek klasy bazowej możemy obsługiwać tym samym blokiem również wszystkie wyjątki klas pochodzących od niej (pochodnych). W C++ wymaga to użycia funkcji wirtualnych :] (jak można zobaczyć tutaj). Python po prostu - tak działa :) Jest to jego naturalne zachowanie, o które nie musimy w żaden sposób zabiegać.

Python - hermetyzacja, enkapsulacja z punktu widzenia programisty C++

W C++ kiedy chcieliśmy ukrywać informacje w klasach pisaliśmy po prostu metody (settery i gettery), które ustawiały lub pobierały wartości konkretnych parametrów. Właściwie - tworząc prywatny atrybut klasy (zaczynający się od dwóch podkreśleń) i pisząc do niego gettery i settery możemy dosłownie przekopiować rozwiązanie znane nam z C++. Możesz nadal pisać
obiekt.setX(10)
obiekt.getX()

Jednak :) Python umożliwia Ci używanie obiektu tak jakby był publiczny:
obiekt.x = 10
obiekt.x

dopisując do nich funkcje, wywoływane w trakcie przypisywania wartości lub odwoływania się do niej. Wszystko dzięki strukturze property.
Stwórzmy więc naszą klasę :) chowając w niej prawdziwe zmienne.
class Klasa(object):
    def __init__(self):
        self.__x = None

    def getx(self):
        return self.__x

    def setx(self, value):
        self.__x = value

    def delx(self):
        del self.__x

    x = property(getx, setx, delx, "I'm the 'x' property.")
Podczas tworzenia obiektu zostanie powołany do życia prywatny atrybut __x. Nie ma do niego dostępu z zewnątrz. Teraz - piszemy normalne metody takie jak w C++ :) getx, która zwróci jego wartość, setx, która ustawi jego wartość oraz dodatkowo delx, która skasuje atrybut :]
Cała "sztuczka" opiera się na końcowym stworzeniu atrybutu klasy "x" i przypisania do niego stworzonego gettera, settera, "delletera" oraz docstringa - opisu zmiennej. Od teraz możemy korzystać z "x" tak jakby był to atrybut klasy faktycznie jednak wywoływały się będą stworzone przez nas funkcje :)
obiekt = Klasa()
obiekt.x = 10 # Wywoła się tak naprawdę setx(10) self.__x = 10
print obiekt.x # Wywoła się tak naprawdę getx() return self.__x
del obiekt.x # Wywoła się tak naprawdę delx() del self.__x
Bardzo przyjemna i użyteczna metoda :] kontrolowania dostępu do atrybutów z zewnątrz przy niekomplikowaniu elegancji oraz prostoty składni :)

Python - klasy z punktu widzenia programisty C++

Kiedy tworzyliśmy klasę w C lub C++ używaliśmy słowa kluczowego class lub struct (od tego zależał domyślny tryb widoczności dla elementów klasy). Trzeba było zapisać co jest private, co protected a co public. Czasami potrzebowaliśmy aby jakaś metoda lub atrybut klasy był statyczny. Do wszystkiego używaliśmy specjalnych słów kluczowych. Jeżeli chcieliśmy stworzyć konstruktor tworzyliśmy metodę o nazwie naszej klasy a destruktor - podobnie, tyle tylko, że nazwę tą poprzedzaliśmy tyldą.

Wszystko omówię na podstawie przykładowej klasy Pythona.

class MojaKlasa(object):
    zmienna_statyczna = 12

    def __init__(self):
        self.zwykla_zmienna = 'a'
        print 'Ja się wywołam przy toworzeniu'

    def __del__(self):
        print 'Ja się wywołam przy usuwaniu'

Powyższa klasa dziedziczy po object. Dalej w ciele klasy definiujemy zmienną o nazwie zmienna_statyczna i przypisujemy jej wartość 12. W języku Python wszystkie zmienne definiowane w ciele klasy zachowują się jak zmienne statyczne. Metoda __init__ (nazwa zaczyna się i kończy od dwóch podkreślników) wywoła się zaraz po utworzenia obiektu :) Zaś metoda __del__  podczas jego usuwania. Piszę celowo "wykona się zaraz po utworzeniu", a nie "jest konstruktorem" ponieważ jest to stwierdzenie bliższe prawdzie.

Metody statyczne oznaczamy podając przed ich deklaracją @staticmethod:

class Klasa(object):
    zmienna = 12

    @staticmethod
    def mojaStatycznaMetoda():
        return Klasa.zmienna
Metoda jak widać nie przyjmuje parametru self (nie miałoby to sensu skoro jest statyczna i może być wywołana dla klasy bez tworzenia jej instancji). Aby odwołać się w niej do zmiennej statycznej możemy użyć Klasa.zmienna gdzie klasa to nazwa klasy a zmienna to nazwa zmiennej zadeklarowanej w jej ciele. Podobnie wygląda wywołanie metody statycznej Klasa.mojaStatycznaMetoda().

Wszystkie metody przyjmują jako pierwszy parametr self, czyli "samego siebie". Jest to jawny zapis tego co w C++ jest ukryte w mechanizmach języka i traktowane "domyślnie" (wszak możesz w metodach klasy C++ odwoływać się do obiektu z użyciem słówka this chociaż nigdzie go nie przekazujesz). Wszystkie atrybuty zdefiniowane w metodzie __init__ z użuyciem self.nazwa_zmiennej są jak widać zmienny obiektu nie klasy co po przeanalizowaniu znaczenia zmiennej self (ja, moja instancja, aktualnie tworzony obiekt) ma rzeczywiście sens :) Zmienne należą do obiektu (self), są definiowane dla niego (konkretnej instancji) nie zaś w ciele samej klasy.

A co z atrybutami: prywatny, publiczny. Domyślnie wszystkie metody i atrybuty w Pythonie są publiczne. I tutaj, aby zdefiniować elementy prywatne, zrezygnowano ze słów kluczowych na rzecz konwencji. Aby element klasy był prywatny jego nazwa musi zaczynać się od dwóch podkreślników to jest od __.  Tak więc atrybuty:


class KolejnkaKlasa(object):
    __zmienna_statyczna
    def __init__(self):
        self.__top_secret

    def __nie_wywolasz_mnie(self):
        pass
    pass
Wszystko czego nazwa zaczyna się od dwóch podkreślników będzie prywatne, ze swojej natury.
Co można powiedzieć o wartościach protected ? Są - ale istnieją jedynie z umowy. Umownie - wszystko czego nazwa rozpoczyna się od jednego znaku podkreślenia jest parametrem chronionym. Umowanie - ponieważ faktycznie ma się do niego nadal publiczny dostęp. Czy to znaczy, że Python nie wspiera metod i atrybutów chronionych w klasach. Tak - w Pythonie nie zaimplementowano tego mechanizmu. Zrobiono to celowo. Zainteresowanych odsyłam do wątku "Protected Methods and Python" na grupie dyskusyjnej języka. Jak widać po dyskusji, ufając intuicji autorytetu jakim jest Bjarne StrouStrup (twórca języka C++) atrybty i metody chronione to zły, zbędny mechanizm :) Więc nie martw się nic nie tracisz :)

Python - funkcje i zmienne z punktu widzenia C++

Będąc pod wrażeniem Thinking in Python chciałem tym wpisem rozpocząć pewne rozważania, które powinny być spostrzeżeniami programisty C/C++ po zderzeniu się z językiem Python.

Języki C/C++ wymagały od nas definiowania funkcji w bardzo restrykcyjny sposób. Musieliśmy podać dokaładnie typ i kolejność przekazywanych parametrów. Zmiana, którejś z tych dwóch powodowało przeładowywanie funkcji. Dodatkowo wymagane było od nas podanie wartości, którą miała zwracać nasza funkcja. Przez co czasami musieliśmy pisać kilka wersji naszej funkcji.

W języku Python wszystko wygląda znacznie prościej. Dlaczego ? Otóż tak jak w języku C/C++ zmienne posiadały konkretny typ - taki a nie inny, w języku Python spotykamy się z pewną szczególną cechą zmiennych. Po pierwsze nie definiujemy explicite ich typów. Są one "rozpoznawane" a może raczej "przyjmowane" przez język programowania na podstawie wartości jakie im przypiszemy.

Co to dla nas oznacza ? Aby w C/C++ stworzyć jakąś uniwersalną funkcję działającą dla różnych typów przekazywanych do niej obiektów musieliśmy używać mechanizmu szablonów. Ponieważ tutaj tworząc funkcję nie podajemy typów parametrów jakie przekazujemy - nasza funkcja działa dla wszystkich danych dla niej przekazanych - o ile operacje, które w niej wykonujemy mają dla tych zmiennych sens.

Dobrym przykładem prezentującym jest na przykład operacja "dodawania" (+).
Dla zmiennej typu string oznacza ona konkatencję (połączenie dwóch napisów).
Dla liczb oznacza to naturalnie ich dodanie.

Rozważmy funkcję dodającą dwie wartości:


def add(a, b):
    return a + b


Nigdzie nie podaliśmy typu zmiennej. Super spróbujmy więc podać wartości różnych typów - zobaczymy co dostaniemy:

add(2,3)

zwróci nam na pewno 5. No dobrze, ale czy zadziała dla liczb zmiennoprzecinkowych ? Oczywiście - jedyny wymaganiem Pythona jest tutaj aby operator, którego używamy (u nas +) był dobrze zdefiniowany dla obiektów, które przekazujemy do funkcji :) z liczbami rzeczywistymi nie ma tutaj problemu.

add(0.1,7.4)

da nam 7.5 :] pięknie. Ba więcej !

add((3 + 2j), (7 + 1.7j))

da nam równie dobry wynik - (10 + 3.7j) :] zgodnie z zasadą - jeżeli dla jakiegoś typu przekazanego do funkcji operacje, które na nim wykonujemy są dobrze określone - wszystko zadziała.
Do tej pory używaliśmy tylko parametrów liczbowych :) Jednak gdyby tak pomyśleć - to operator + jest równie dobrze określony dla napisów - oznacza on po prostu ich konkatenację. Czyli "Merry" + " Christmas" powinno nam wyprodukować "Merry Christmas". Sprawdźmy.

add('Marry', ' Christmas')

Działa :)

Jak widać Python pozawala na tworzenie funkcji, których zachowanie jest bardziej naturalne a wyniki dokładnie takie jakie się spodziewamy :] Specjalne mechanizmy, które służyły nam do osiągnięcia podobnego efektu w C++ zostały jakby "wchłonięte" w naturalne zachowanie się języka programowania.
Zasada iż operatory i działania jakie wykonujemy na obiektach przekazywanych do funkcji tyczy się również tworzonych przez nas typów. Python pozwala na przeładowywanie i definiowanie całego grona operatorów pozwalających nam sterować zachowywaniem się tworzonym przez nas typów danych. Jedną z dostępnych w dokumentacji list takich operatorów znajdziesz pod adresem http://docs.python.org/library/operator.html

Polimorfizm w Pythonie

Ostatnio programując w C++ walczyłem z polimorficznymi wyjątkami. Sytuacja zgrała się z trafieniem po drodze na lekturę Thinking in Python, gdzie zauważyłem bardzo ciekawe podejście autora, który czasami pisze "w C++ musiałeś to i to a w Pythonie - po prostu działa". Szalenie mi to podejście odpowiada :) Tak więc w myśl tej idei postanowiłem sprawdzić jak ma się polimorfizm wyjątków w Pythonie i czy dużo więcej się namęcze. Po raz kolejny :) punkt za prostotę dla Pythona - po prostu działa :]
class MyException(Exception):
    def __init__(self, message):
        self.message = message
    def __str__(self):
        return repr(self.message)

class MySocketException(MyException):
    pass

class MyOtherException(MyException):
    pass

def f():
    raise MyOtherException("Moj wyjatek: Wystapil straszny blad !")

if __name__ == '__main__':
try:
    f()
except MyException, e:
    print e



Czy to nie jest piękne :)

Sunday, December 21, 2008

Polimorficzne wyjątki w C++

Dziś pisałem zaliczenie z Interfejsów Programowania Systemów Operacyjnych. Zadanie na kolejne laboratorium polegało na opakowaniu w klasę prostej komunikacji opartej na socketach uniksowych. Może się komuś przyda :) Programik znajdziecie tutaj. Najwięcej namęczyłem się z obsługą wyjątków :) Nie jest to wyjście idealne, ale :) jeżeli ktoś nie ma lepszego pomysłu to można podejrzeć jak to jest wykonane. Przy okazji szukania trafiłem dziś na ciekawą informację o polimorficznych wyjątkach w FAQ LITE C++.

Python - od czego zacząć

Dziś zostało mi zadane pytanie od czego zacząć z Pythonem na start :)
Ponieważ  było to pytanie w kontekście "Windowsa" będę pisał głównie o nim.

Na początek potrzebny jest sam język Python. Możemy go ściągnąć z oficjalnej strony
Po zajerzeniu do działu Download możemy się ciut zagubić. Proponuję ściągnąć wersję pythona zaczynającą się od cyferki 2. Wszystkie samouczki opisują składnię kompatybilną z tą właśnie gałęzią. I nie ma się co martwić. Python 3 wyszedł stosunkowo nie dawno jest do niego niewiele bibliotek i chyba niemalże brak samouczków, a ucząc się Pythona 2 wcale nie uczysz się czegoś nieużytecznego. Opanowując Pythona 2 dasz sobie radę i z Pythonem 3 wspierając się dokumentacją :) opisującą zmiany pomiędzy tymi dwoma gałęziami.

Ściągamy więc ze strony http://www.python.org/download/ wersję Pythona 2, instalujemy w systemie :) Super. Połowa sukcesu za nami.

Przydałoby się jeszcze środowisko programistyczne. Sporo o edytorach dla języka Python można znaleźć w wątku http://forum.python.org.pl/index.php?topic=54.0 PPCG lub na oficjalnym Wiki Pythona . Wybór należy do Ciebie. Jeżeli lubisz proste, działające programy polecam Geany. Zaś dla miłośników poważny środowisk programistycznych wtyczkę do Eclipse o nazwie PyDev. W gruncie rzeczy bardzo dobrze z Pythonem radzi sobie Vim. Wiedząc, że kombinacja klawiszy [ctrl]+[x] [o] uzupełnia składnię wielu funkcji pythona (choć niestety są tutaj zauważalne braki) podając również w okienku nad kodem jej dokumentację (brawo !) a [ctrl]+[n] uzupełnia na podstawie wpisanego już w kodzie lub plikach tekstu - można śmiało używać Vima. Przy odpowiednich ustawieniach wcięcia :) i kolorowanie - no niemalże nic nie brakuje.
Znacznie bardziej rozbudowany jest na przykład Eclipse, który zaznacza nam na "marginesie" kodu wszystkie linijki nie zgodne ze standardem kodowania PEP-8, posiada znacznie bardziej wyrafinowane uzupełnianie składni oczywiście moc funkcji konfiguracyjnych.

Należałoby tutaj wspomnieć o pewnej wciąż drażniącej mnie przypadłości Windows. Konsola i PATH :| Wieczne utrapienie. Problem polega między innymi na tym, że programy uruchamia się na przykład wpisując:

python moj_program.py
Po pierwsze żeby konsola była zjadliwa wypadałoby użyć Windows PowerShell i zmienić w niej czcionkę na coś bardziej zjadliwego. Ja używam Lucida Console 14 bez pogrubienia. Zaletą tej konsoli jest fakt iż można w niej stosować polecenia takie jak na przykład ls nie walcząc z Uniksowymi nawykami. Jednak nadal uruchomienie konsoli Pythona czy wykonanie w niej programu w którymś momencie spowoduje odpaleniem go w zwykłej konsoli cmd i cały urok gdzieś znika :| nie udało mi się jeszcze zmusić całego systemu aby używał wszędzię PowerShella.
Kolejny frustrujący, tym razem już prostszy do rozwiązania problem, to fakt, że domyślnie polecenie Python nie jest wrzucone do zmiennej PATH. Możemy to zmienić wchodząc we Właściwości Mojego Komputera (Właściwości Systemu), wybierając w zakładce Zaawansowane opcje Zmienne środowiskowe ... i modyfikując  lub dodając zmienną użytkownika PATH na przykład:

%PATH$:%ProgramFiles%\Python26\

Przynajmniej tak to wygląda pod Vistą w przypadku instalacji w domyślnym katalogu Program Files.
Oczywiście to nie rozwiązuje poprzedniego problemu i nadal mamy totlotek, z której konsoli będziemy korzystać :| Jeżeli ktoś potrafi rozwiązać rzeczone problemy :) to byłbym szalenie wdzięczny za uwagi w komentarzach. Jednak z mojego doświadczenia nic nie równa się z wygodą używania Pythona w Linuksie. Więc jeżeli masz dostęp do jakiegoś shella lub możliwość używania Linuksa ad hoc - skorzystaj z niego :) Pod Windows najwygodniej pracować jest w jakimś edytorze, który posiada swój własny shell i wyjście programu tak aby nie musieć używać linii poleceń Windows (o zgrozo).

Gdzie zacząć szukać. Ja zacząłem od kursu Jakuba Swachy - był przyjemny. Polecam również moje wykłady. Jeżeli zaś chodzi o dobrą literaturę - natknąłem się w sieci na draft Thinking In Python. Już programujący i niebojącym się języka Angielskiego - bardzo polecam. Mnóstwo materiałów znajdziecie rownież na stronie Polish Python Coders Group szczególnie w dziale artykuły i wykłady.

Powodzenia !

Saturday, December 20, 2008

web2py - wymiękłem

Jeszcze tydzień temu zachwalałem, w swojej prezentacji, na konferencji w Warszawie Pylons. Prezentowałem jego cechy, zalety oraz braki. No właśnie braki. Po obejrzeniu prezentacji Webhosting.pl o wdrożeniu Pylons oraz "Pylons - Demonstracja możliwości" Tomasza Nazara. Można je znaleźć na stronie materiałów PyCon2008 PL zaczęło do mnie docierać, że Pylons nie jest niczym - fenomenalnym.

Zacząłem analizować ... porównania. Porównania z innymi frameworkami. W Merb zachwyciła mnie modularność, wydajność i czytelność kodu. Przyznaję się. Nie napisałem w tym frameworku nawet pół linijki kodu. Cały podziw dla kunsztu przedkładam wyłącznie z wypowiedzi z jakimi spotykam się w sieci. Przeglądając pluginy znalazłem ciekawą opcję walidacji danych wchodzących do datamapeera jednak zabrakło mi gdzieś generowania formulrzy czy chociażby samej obecności admin panelu. Wiem, że ma być obecny w wersji 2.0 :) To cieszy. Być może coś przeoczyłem jednak przy moich obecnych obserwajach Merb w porównaniu do Pylons ma fantastyczne validowanie, z tłumaczeniami błędów i to w kilku języka... I do tego ta elegancja składni dekoratorów - miodzio.

No właśnie. Skoro już przy tym jesteśmy. Pylons tak jak merb nie posiada admin panelu. Tutaj na tle frameworków Pythonowych króluje Django. Nie ma mowy o scaffoldingu czy czymkolwiek takim. Nic z tych rzeczy. Modularność może cieszyć, jednak niestety nie znajdujemy mechanizmów do generowania formularz (znowu) ... Co prawda jest FormBuild ale wygląda bynajmniej podejrzanie, pomimo tego że jest opisana w PylonsBook, i jakoś ... nie o takim generowaniu marzę.

No więc może Django. Posiadania rozbudowane generowanie formularzy oraz admin panel. Pomimo tego nie dorasta do pięt Pylons w walidowaniu formularzy o braku możliwości testowania kodu (co często jest krytczne) nie wspomnę.
Sprostowanie
Od wersji 1.0 Django posiada możliwość pisania zarówno unittestów (z użyciem Pythonowej biblioteki unittest) jak i functional testów. Jest temu poświęcony poddział dokumentacji.

Co do Railsów - wydają się tutaj rozsądne. Posiadają na przykłąd mailer, którego na próżno szukać w jakimkolwiek pythonowym frameworku. Jest konsola (jak w Pylons), Scaffolding. Może brak admin panelu (chociaż może ktoś zna takowy), ale nie ma co narzekać: mailer, rack do testowania, migracje. HAML, SASS, spory wybór możliwych do podpięcia ORMów ... bomba.
A co gdybyśmy chcieli programować w Pythonie ? HAML i SASS oczywiście nie zagościł tutaj, mailerów nie można się spodziewać (choć szkoda, bo przydałaby się dobrze przetesowana biblioteka odporna na MailInjection) .

Wszystkie frameworki są do siebie jednak podobne. Generowany jest jakiś kod, używa się poleceń skryptowych i konsoli...
Dziś trafiłem na ten screencast pokazujący możliwości frameworka web2py



Nie wiem jakie macie podejście do tego co jest na nim pokazane. Wszystko co jest tam zaprezentowane to prawda, choć bardziej przypomina to "klikanie" aplikacji, niż jej tworzenie. Na prawdę. Nie otworzyłem ani przez sekundę edytora. Konsola też w gruncie rzeczy jest zbędna (chyba, że chcesz w niej odpalić serwer). Jest scaffolding (wow). Co prawda nie zauważyłem, żeby można było sobie wygenerować jego kod do pliku "od tak" jak w Rails, ale jest ! i to nie lada. Formularzy się "nie generuje" po prostu ... są :) i walidowanie jest ... bajecznie proste.
Wydaje mi się troszkę, że tak zautomatyzowany framework będzie podpadał pod zarzuty pod jakimi padał Django w ogniu Grono.net jednak ... to co dziś widziałem robi na mnie wrażenie. Web2Py to coś ... innego, coś co zmienia myślenie o tworzeniu aplikacji internetowych. Zobaczymy co jeszcze :)

Monday, December 1, 2008

Python Wykłady - uaktualnienie

Moja wiedzy o Pythonie wciąż się poszerza a wraz z nią zmieniają się wykłady.
W części pierwszej zmieniłem troszkę "wypunktowanie" pythona na jego korzyść - doszedłem do wniosku, że Python posiada dobry edytor po tym jak zobaczyłem pydev w Eclipse oraz usłyszałem opinie o Komode IDE - jest to moim zdaniem porównywalne z programem Zenda oraz PDT.

Poprawiłem kilka błędów, które zauważyli moi znajomi. Dodałem opis or, not i and w części drugiej zaraz przy omówieniu ifów.

W części trzeciej dodałem do klas informacje o tym jak enkapsulować zmienne w Pythonie :) Coś czego dopiero nie dawno się nauczyłem.