2011-06-18 13 views
13

Wydaje się, że nie ma dobrej dokumentacji online na ten temat: Jeśli utworzyć klasy pochodnej, automatycznie będzie mieć wszystkie atrybuty klasy podstawowej? Ale co to jest BaseClass.__init() dla, czy trzeba to zrobić również do innych metod klasy bazowej? Czy argumenty są potrzebne w przypadku BaseClass.__init__()? Jeśli masz argumenty dla swojej klasy bazowej __init__(), czy są one również używane przez klasę pochodną, ​​czy musisz jawnie ustawić argumenty na pochodnej klasy klas __init__(), czy zamiast tego ustawić je na BaseClass.__init__()?Atrybuty klas i baz klasy w języku Python?

Odpowiedz

9

If I make a derived class, will it automatically have all the attributes of the base class?

Atrybuty klasy, tak. Atrybuty instancji, nie (po prostu dlatego, że nie istnieją, gdy klasa jest tworzona), chyba że nie istnieje __init__ w klasie pochodnej, w którym to przypadku zostanie wywołany podstawowy i ustawi atrybuty instancji.

Does BaseClass.init() need arguments?

Zależy od klasy i jej podpisu __init__. Jeśli jawnie wywołasz Base.__init__ w klasie pochodnej, będziesz musiał przynajmniej podać self jako pierwszy argument. Jeśli masz

class Base(object): 
    def __init__(self): 
     # something 

to jest to raczej oczywiste, że żadne inne argumenty są akceptowane przez __init__. Jeśli chcesz mieć

class Base(object): 
    def __init__(self, argument): 
     # something 

następnie trzeba przejść argument Dzwoniąc bazę __init__. Brak tu nauki o rakietach.

If you have arguments for your base class init(), are they also used by the derived class, do you need to explicitly set the arguments to the derived classe's init(), or set them to BaseClass.init() instead?

Ponownie, jeśli, klasy nie __init__, bazową będzie używany.

W innym przypadku należy się tym zająć w jakiś sposób. Niezależnie od tego, czy używasz *args, **kwargs i po prostu przekazujesz argumenty niezmodyfikowane do klasy bazowej, lub kopiujesz sygnaturę klasy podstawowej, lub dostarczasz argumenty z innych źródeł, zależy to od tego, co próbujesz osiągnąć.

43

Jeśli zaimplementujesz __init__ w klasie pochodnej od BaseClass, to nadpisze ona odziedziczoną metodę __init__, dzięki czemu BaseClass.__init__ nigdy nie zostanie wywołana. Jeśli potrzebujesz wywołać metodę BaseClass (jak zwykle), to do niej należy to zrobić, i zrobić to jawnie, wywołując BaseClass.__init__, zwykle z nowo wprowadzonej metody __init__.

class Foo(object): 
    def __init__(self): 
     self.a = 10 

    def do_something(self): 
     print self.a 

class Bar(Foo): 
    def __init__(self): 
     self.b = 20 

bar = Bar() 
bar.do_something() 

To spowoduje następujący błąd:

AttributeError: 'Bar' object has no attribute 'a' 

Więc metoda do_something zostało odziedziczone zgodnie z oczekiwaniami, ale ta metoda wymaga atrybut a zostały ustawione, które nigdy to dlatego __init__ również został nadpisany. Obejdziemy to przez jawne wywołanie Foo.__init__ z poziomu Bar.__init__.

class Foo(object): 
    def __init__(self): 
     self.a = 10 

    def do_something(self): 
     print self.a 

class Bar(Foo): 
    def __init__(self): 
     Foo.__init__(self) 
     self.b = 20 

bar = Bar() 
bar.do_something() 

która drukuje 10 zgodnie z oczekiwaniami.Foo.__init__ w tym przypadku oczekuje jednego argumentu instancją Foo (który nazywa się umownie self).

Normalnie, gdy wywołanie metody na instancji klasy, instancja klasy jest przekazywana automatycznie jako pierwszy argument. Metody dotyczące instancji klasy nazywają się związanymi metodami. bar.do_something jest przykładem metody związanej (i zauważysz, że jest wywoływana bez żadnych argumentów). Foo.__init__ to niezwiązana metoda , ponieważ nie jest dołączona do konkretnej instancji Foo, więc pierwszy argument, instancja Foo, musi zostać przekazany jawnie.

W naszym przypadku, mijamy self do Foo.__init__, który jest instancją Bar, który został przekazany do metody __init__ w Bar. Ponieważ Bar dziedziczy po Foo, instancje Bar są również instancjami Foo, więc przekazanie self do Foo.__init__ jest dozwolone.

Jest prawdopodobne być tak, że klasa jesteś dziedziczenie z wymaga lub akceptuje więcej argumentów niż tylko instancji klasy. Są one traktowane tak samo, jak w przypadku każdego sposobu ty dzwonisz ciągu __init__:

class Foo(object): 
    def __init__(self, a=10): 
     self.a = a 

    def do_something(self): 
     print self.a 

class Bar(Foo): 
    def __init__(self): 
     Foo.__init__(self, 20) 

bar = Bar() 
bar.do_something() 

co drukować 20.

Jeśli próbujesz zaimplementować interfejs, który w pełni odsłania wszystkie argumenty inicjalizacji klasy bazowej za pośrednictwem swojej klasie dziedziczenie, trzeba zrobić tak wyraźnie. Zwykle robi się to z argumentami * args i ** kwargs (nazwy są według konwencji), które są symbolami zastępczymi dla wszystkich pozostałych argumentów, które nie są jawnie nazwane. Poniższy przykład wykorzystuje wszystko Rozmawiałem:

class Foo(object): 
    def __init__(self, a, b=10): 
     self.num = a * b 

    def do_something(self): 
     print self.num 

class Bar(Foo): 
    def __init__(self, c=20, *args, **kwargs): 
     Foo.__init__(self, *args, **kwargs) 
     self.c = c 

    def do_something(self): 
     Foo.do_something(self) 
     print self.c 


bar = Bar(40, a=15) 
bar.do_something() 

W tym przypadku argument c jest ustawiony na 40, ponieważ jest to pierwszy argument Bar.__init__. Drugi argument następnie wprowadza się do zmiennych args i kwargs (* i ** jest specyficzny składnia mówi rozszerzyć listy/krotki lub słownika do odsunięte podczas przechodzenia do funkcji/metodą) i jest przekazywana do Foo.__init__.

Ten przykład powoduje, że nadpisana metoda musi być wywoływana jawnie, jeśli jest to wymagane (ponieważ w tym przypadku jest to do_something).

Jeden ostatni punkt, często widzisz super(ChildClass, self).method() (gdzie ChildClass jest dowolną dowolną klasą podrzędną) zamiast wywołania metody BaseClass jawnie. Omówienie super jest zupełnie inna kwestia, ale wystarczy powiedzieć, w tych przypadkach to zazwyczaj używane do zrobić dokładnie to, co jest robione przez wywołanie BaseClass.method(self). Krótko mówiąc, super deleguje wywołanie metody do następnej klasy w kolejności rozwiązywania metody - MRO (która w pojedynczym dziedziczeniu jest klasą nadrzędną). Zobacz documentation on super, aby uzyskać więcej informacji.