2014-10-20 15 views
9

Potrei venire da una mentalità diversa, essendo principalmente un programmatore C++. Questa domanda ha a che fare con OOP in Python e in particolare con metodi virtuali puri. Prendendo il codice che ho adattato da this question sto guardando questo campione di base.Le funzioni virtuali pure Python sono possibili e/o ne valgono la pena?

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() 

In questo modo viene chiamata la funzione parla per diverse classi derivate. Ora il mio problema è che digitando anatra è tutto buono e penso di averlo afferrato. Tuttavia, è sbagliato perseguire un OOP più rigoroso in Python? Così ho visto lo Abstract Base Classes e in particolare lo abstractmethod. A me sembra che tutto questo mi consenta di chiamare il metodo della classe base con super. Esiste un modo/ragione (in Python) per rendere puro speak() tale che l'implementazione di un animale derivato senza parlare possa generare un errore?

La mia argomentazione a favore di una tale ricerca sarebbe quando si scrivono moduli e framework che si intendono le persone in sottoclasse, questo potrebbe autocertificare per loro il fatto che è necessario implementare la funzione. Probabilmente un'idea molto brutta è una cosa del genere, visto che la funzione "pura" della classe base genera un'eccezione. Il problema è che questo errore si trova in fase di esecuzione!

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

Per quanto posso vedere, ciò che si descrive è esattamente ciò che 'abstractmethod' fa. Puoi chiarire cosa vuoi che 'abstractmethod' non fornisca? Non otterrete una soluzione "compile-time" per niente, perché Python non ha realmente un tempo di compilazione nel senso C++. Ma 'abstractmethod' consente di ottenere l'errore quando la classe è definita (prima che sia istanziata). – BrenBarn

+0

@BrenBarn Si scusa per la maldestra dichiarazione. So che non avrò errori nella compilazione del tempo. È bello sapere che posso ottenere un errore quando l'oggetto astratto della classe base o un oggetto classe derivato non valido viene istanziato. Il mio errore era usare un interprete Python 3 che faceva sembrare che abstractmethod non facesse nulla perché non stavo definendo la classe nel modo corretto in Python3. Vedi la risposta accettata. – benzeno

+0

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

risposta

15

classi base astratte già fanno quello tu vuoi. abstractmethod non ha nulla a che fare con la possibilità di chiamare il metodo con super; puoi farlo comunque. Invece, i metodi decorati con abstractmethod devono essere sovrascritte per una sottoclasse di essere istanziabile:

>>> 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, questo è quello che stavo cercando. Il mio errore era pensare che Python2 e 3 non fossero estremamente diversi. Probabilmente ho erroneamente etichettato questa domanda, ma Python 3 lascia semplicemente correre senza sollevare nulla. A meno che non chiami 'class Foo (metaclass = ABCMeta):'. Ho quindi frainteso quale fosse il metodo abstractmethod perché i documenti Python2 hanno commentato su super e non ho potuto vedere se stava facendo qualcos'altro. Grazie. – benzeno

6

Il problema è che questo errore si trova in fase di esecuzione!

Bene, è Python ... la maggior parte degli errori verrà mostrata in fase di esecuzione.

Per quanto ne so, il modello più comune per affrontare è in Python è fondamentalmente ciò che si descrive: basta avere il metodo speak della classe base un'eccezione:

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

+1 per "la maggior parte degli errori si presenteranno in fase di esecuzione"! –

+0

Okay ... mi dispiace che sia stato maldestro. Non ho mai pensato diversamente. Speravo solo in secondo luogo, quindi quando un oggetto viene istanziato rispetto a dopo, quando si effettua una chiamata per parlare. – benzeno

Problemi correlati