2014-10-20 21 views
9

Mogę pochodzić z innej mentalności, będąc przede wszystkim programistą C++. To pytanie dotyczy OOP w Pythonie, a dokładniej czystych wirtualnych metod. Tak więc biorąc kod, który zaadaptowałem z this question, patrzę na tę podstawową próbkę.Czy są możliwe czyste i wirtualne funkcje Pythona?

class Animal(): 
    def speak(self): 
     print("...") 

class Cat(Animal): 
    def speak(self): 
     print("meow") 

class Dog(Animal): 
    def speak(self): 
     print("woof") 

my_pets = [Dog(), Cat(), Dog()] 

for _pet in my_pets: 
    _pet.speak() 

Widać więc, że wywołuje funkcję mowy dla różnych klas pochodnych. Teraz mój problem polega na tym, że pisanie na kaczce jest dobre i myślę, że to zrozumiałem. Czy jednak błędem jest ściganie bardziej restrykcyjnego OOP w Pythonie? Popatrzyłem więc na Abstract Base Classes, a konkretnie na abstractmethod. Wydaje mi się, że to wszystko pozwala mi nazywać metodę klasy bazowej super. Czy istnieje jakiś sposób/powód (w języku Python), aby uczynić speak() czystym takim, że implementacja zwierzęcia wyprowadzonego bez mówienia spowodowałaby błąd?

Mój argument za takim pościgiem polegałby na tym, że pisząc moduły i ramy, które zamierzasz podklasować ludziom, to sam udokumentowałby im fakt, że potrzebują implementacji funkcji. Prawdopodobnie bardzo złym pomysłem jest coś takiego, ponieważ funkcja "czystej" klasy podstawowej rzuca wyjątek. Problem polega na tym, że ten błąd został wykryty w czasie wykonywania!

class VirtualException(BaseException): 
    def __init__(self, _type, _func): 
     BaseException(self) 

class Animal(): 
    def speak(self): 
     raise VirtualException() 

class Cat(Animal): 
    def speak(self): 
     print("meow") 

class Dog(Animal): 
    def speak(self): 
     print("woof") 

class Wildebeest(Animal): 
    def function2(self): 
     print("What!") 

my_pets = [Dog(), Cat(), Dog(), Wildebeest()] 

for _pet in my_pets: 
    _pet.speak() 
+1

O ile widzę, co można opisać to dokładnie to, co robi abstractmethod' '. Czy możesz wyjaśnić, czego nie ma "abstractmethod"? Nie dostaniesz rozwiązania "kompilacji" na nic, ponieważ Python tak naprawdę nie ma czasu na kompilację w sensie C++. Ale 'abstractmethod' pozwala uzyskać błąd, gdy klasa jest zdefiniowana (zanim zostanie utworzona). – BrenBarn

+0

@BrenBarn Tak przepraszam za niezręczne stwierdzenie. Wiem, że nie dostanę błędów podczas kompilacji. Miło jest wiedzieć, że mogę uzyskać błąd, gdy zostanie utworzony obiekt abstrakcyjnej klasy podstawowej lub niepoprawny obiekt klasy pochodnej. Mój błąd polegał na używaniu interpretera Python 3, który sprawiał, że abstractmethod wydawał się nic nie robić, ponieważ nie definiowałem klasy w prawidłowy sposób Python3. Zobacz zaakceptowaną odpowiedź. – benzeno

+0

Powiązane: http://stackoverflow.com/questions/4714136/python-how-to-implement-virtual-methods/38717503 –

Odpowiedz

15

Abstrakcyjne klasy bazowe już robić to, co chcesz. abstractmethod nie ma nic wspólnego z wywoływaniem metody za pomocą super; możesz to mimo wszystko zrobić. Zamiast tego, wszelkie metody ozdobione abstractmethod musi być zastąpiona przez podklasę być chwilowe:

>>> class Foo(object): 
...  __metaclass__ = abc.ABCMeta 
...  @abc.abstractmethod 
...  def foo(self): pass 
... 
>>> class Bar(Foo): pass 
... 
>>> class Baz(Bar): 
...  def foo(self): return super(Baz, self).foo() 
... 
>>> Foo() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: Can't instantiate abstract class Foo with abstract methods foo 
>>> Bar() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: Can't instantiate abstract class Bar with abstract methods foo 
>>> Baz() 
<__main__.Baz object at 0x0000000001EC10B8> 
+0

OK, tego właśnie szukałem. Mój błąd polegał na tym, że Python2 i 3 nie były skrajnie różne. Prawdopodobnie błędnie oznaczyłem to pytanie, ale Python 3 po prostu uruchamia to bez podnoszenia czegokolwiek. Chyba że nazwiesz 'class Foo (metaclass = ABCMeta):'. Wtedy źle zrozumiałem, o co chodzi w abstractmethod, ponieważ doktorzy Python2 komentowali super i nie mogłem zobaczyć, czy robi on coś innego. Dzięki. – benzeno

6

Problem jest to, że ten błąd występuje przy starcie!

Cóż, to Python ... większość błędów pojawi się w czasie wykonywania.

O ile mi wiadomo, najczęściej wzór do czynienia ze jest w Pythonie jest w zasadzie to, co można opisać: wystarczy mieć speak metoda klasy bazowej wyjątek:

class Animal(): 
    def speak(self): 
     raise NotImplementedError('You need to define a speak method!') 
+2

+1 dla "większość błędów pojawi się w czasie wykonywania"! –

+0

Okay ... Przepraszam, że był niezgrabny. Nigdy nie myślałem inaczej. Po prostu liczyłem na drugie najlepsze, więc kiedy obiekt jest tworzony, w przeciwieństwie do późniejszego, kiedy dzwoni się mówić. – benzeno

Powiązane problemy