Wie Implementierung der Methode in Python zu verlangen?
-
04-10-2019 - |
Frage
Ich verwende Duck Typing in Python.
def flagItem(object_to_flag, account_flagging, flag_type, is_flagged):
if flag_type == Flags.OFFENSIVE:
object_to_flag.is_offensive=is_flagged
elif flag_type == Flags.SPAM:
object_to_flag.is_spam=is_flagged
object_to_flag.is_active=(not is_flagged)
object_to_flag.cleanup()
return object_to_flag.put()
Wenn verschiedene Objekte in als object_to_flag
übergeben werden, von denen alle haben is_active
, is_spam
, is_offensive
Attribute. Sie passieren auch eine cleanup()
Methode haben.
Die Objekte Ich bin in allen vorbei haben die gleiche Basisklasse (sie sind db Objekte in Google App Engine):
class User(db.Model):
...
is_active = db.BooleanProperty(default = True)
is_spam = db.BooleanProperty(default=False)
is_offensive = db.BooleanProperty(default=False)
def cleanup():
pass
class Post(db.Model):
...
is_active = db.BooleanProperty(default = True)
is_spam = db.BooleanProperty(default=False)
is_offensive = db.BooleanProperty(default=False)
def cleanup():
pass
Wie kann ich die cleanup()
Methode abstrakt so machen, dass ich die gleiche Elternklasse für all diese Objekte haben kann, dass die Kinder Implementierung erfordert zur Verfügung stellen?
Vielleicht noch wichtiger ist, ist diese 'pythonic'? Soll ich diesen Weg gehen, oder soll ich vertrauen einfach auf der Ente eingeben? Mein Hintergrund ist in Java und ich versuche, die Python-Art, die Dinge zu lernen.
Danke!
Lösung
Da Sie nicht über abc verfügbar, können Sie dies mit einem einfachen tun können metaclass
class Abstract(type(db.Model)):
def __new__(metacls, clsname, bases, clsdict):
for methodname in clsdict.pop('_abstract_methods_', []):
try:
if not callable(clsdict[methodname]):
raise TypeError("{0} must implement {1}".format(clcname, methodname))
except KeyError:
raise TypeError("{0} must implement {1}".format(clcname, methodname))
return super(Abstract, metacls).__new__(metacls, clsname, bases, clsdict)
class RequireCleanup(db.Model):
__metaclass__ = Abstract
_abstract_methods_ = ['cleanup']
def cleanup(self):
pass
der Ausdruck type(db.Model)
Entschlüssen, was auch immer Metaklasse für db.Model
verwendet wird, so dass wir auf den Google-Code nicht Schritt tun. Außerdem machen wir einen Abstecher _abstract_methods_
aus der Klasse Wörterbuch bevor es bekommen vergangen ist __new__
Methode Google, so dass wir nichts brechen. Wenn db.Model
bereits ein Attribut mit diesem Namen hat, dann müssen Sie es auf etwas anderes ändern.
Andere Tipps
Mit dem abc
Modul . Insbesondere stellen Sie Ihren metaclass auf ABCMeta
der Basisklasse und verwenden Sie die @abstractmethod
Dekorateur auf cleanup
Methode.
Die Debatte darüber, ob dies „pythonic“ ist gespalten. PEP 3119 , die den Standard beschreibt, sind einige der Vor-und Nachteile ( aber offensichtlich begünstigt ABCs). Das machte es in der Standard-Bibliothek, die eine ziemlich gute Anzeichen dafür, dass viele Menschen ist es unter Umständen sinnvoll erachten. In Ihrem Fall, ich denke, es ist angemessen.
Wenn Sie, dass die Bereinigung Verfahren sicherstellen wollen, implementiert ist, können Sie mit dem @abc.virtualmethod
Dekorateur wickeln. Dies wird einen Fehler bei der Instanziierung eines Objekts verursacht, die die virtualmethod nicht außer Kraft gesetzt hat. Dies erfordert auch, dass Sie Ihre Klasse abc.ABCMeta
machen __metaclass__
.
Siehe abc Modul für weitere Informationen und einige Beispiele.
Dies ist nicht allgemein üblich ist: In der Regel gibt es nur Dokumente zu dem Effekt, dass Implementierer die gegebenen Methode außer Kraft setzen muß. Dies kann jedoch zu der Neuheit des abc
Modul mehr fällig (neu in Python 2.6) als ein wahrgenommen unpythonicness diesen Ansatz.
Warum nicht die cleanup
Methode hat gerade ein NotImplementedError
erhöhen, wenn sie aufgerufen wird? Wenn sie Ihre Kinder Klassen arbeiten wollen müssen sie eine Art der Umsetzung in Kraft gesetzt werden.
Obwohl ich es nie persönlich in Anspruch genommen habe, habe ich viele Verweise auf