class Pomarancz(object):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).
pass
class Gruszka(object):
def __new__(type):
return Pomarancz()
if __name__ == '__main__':
gruszka = Gruszka()
print type(gruszka)
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):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).
return object.__new__(type, *args, **kwargs)
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.