Question

J'utilise frappe de canard en 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()

Si différents objets sont passés en tant que object_to_flag, qui ont tous les attributs is_active, is_spam, is_offensive. Ils se aussi d'avoir une méthode de cleanup().

Les objets que je passe dans tous la même classe de base (ils sont des objets db dans 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

Comment puis-je faire la méthode abstraite cleanup() afin que je puisse avoir la même classe parente pour tous ces objets qui exige que les enfants fournissent la mise en œuvre?

Peut-être plus important encore, est-ce « pythonique »? Dois-je aller dans cette voie, ou devrais-je compter uniquement sur la frappe de canard? Mon arrière-plan est en Java et je suis en train d'apprendre la façon de faire les choses Python.

Merci!

Était-ce utile?

La solution

Puisque vous ne avez pas abc disponibles, vous pouvez le faire avec un simple métaclasse

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

l'expression type(db.Model) décide de tout métaclasse pour se habituera db.Model donc nous ne marchez pas sur le code de Google. En outre, nous pop _abstract_methods_ du dictionnaire de classe avant d'obtenir son transmis à Google de méthode __new__ afin que nous ne casse rien. Si db.Model a déjà un attribut avec ce nom, alors vous devrez changer à autre chose.

Autres conseils

Utilisez le abc Module . Plus précisément, réglez la métaclasse de votre classe de base à ABCMeta et utiliser le décorateur @abstractmethod sur votre méthode cleanup.

Le débat sur si cela est « pythonique » est divisé. PEP 3119 , qui décrit la norme, énumère quelques-uns des avantages et des inconvénients ( mais favorise évidemment ABCs). Il fait dans la bibliothèque standard, ce qui est une assez bonne indication que beaucoup de gens jugent utile dans certaines circonstances. Dans votre cas, je pense qu'il convient.

Si vous voulez vous assurer que la méthode de nettoyage est mis en œuvre, vous pouvez envelopper avec le décorateur @abc.virtualmethod. Cela entraînera une erreur sur instanciation d'un objet qui n'a pas surchargé l'virtualmethod. Cela exige également que vous faites abc.ABCMeta la __metaclass__ de votre classe.

Voir la Module abc pour plus d'informations et quelques exemples.

Ceci est généralement pas fait: il y aura généralement juste docs à l'effet que implémentateurs doivent passer outre la méthode donnée. Cependant, cela peut être plus en raison de la nouveauté du module abc (nouveau en Python 2.6) qu'une unpythonicness perçue de cette approche.

Pourquoi ne pas avoir la méthode cleanup soulever juste un NotImplementedError quand on l'appelle? S'ils veulent vos enfants des classes au travail, ils vont devoir mettre une sorte de mise en œuvre en place.

Bien que je ne l'ai jamais utilisé personnellement, je l'ai vu de nombreuses références à

scroll top