質問

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

さまざまなオブジェクトが次のように渡される場合 object_to_flag, 、すべてが持っています is_active, is_spam, is_offensive 属性。彼らはたまたま、 cleanup() 方法。

渡すオブジェクトはすべて同じ基本クラスを持っています (Google App Engine の db オブジェクトです)。

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

どうすれば作れますか cleanup() メソッド抽象を使用すると、子が実装を提供する必要があるこれらすべてのオブジェクトに同じ親クラスを持たせることができますか?

おそらくもっと重要なことは、これが「パイソン的」であるかどうかということです。この方法で進むべきでしょうか、それともダックタイピングに頼るべきでしょうか?私のバックグラウンドは Java で、Python のやり方を学ぼうとしています。

ありがとう!

役に立ちましたか?

解決

ABCを利用できないため、シンプルなメタラスでこれを行うことができます

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

表現 type(db.Model) Metaclassが使用するものはすべて解決します db.Model したがって、Googleのコードを踏むことはありません。また、ポップします _abstract_methods_ Googleに渡される前にクラスの辞書から __new__ 何も壊れないように方法。もしも db.Model すでにその名前の属性を持っているので、それを何か他のものに変更する必要があります。

他のヒント

使用 abc モジュール. 。具体的には、ベースクラスのメタラスを設定します ABCMeta そして、使用します @abstractmethod あなたのデコレーター cleanup 方法。

これが「pythonic」であるかどうかについての議論は分割されています。 PEP 3119, 、標準を説明し、長所と短所の一部をリストします(ただし、明らかにABCを支持します)。それは標準的なライブラリにそれを作りました。これは、多くの人々が状況によってそれを有用であると考えているというかなり良い兆候です。あなたの場合、私はそれが適切だと思います。

クリーンアップ メソッドが確実に実装されるようにしたい場合は、次のようにラップします。 @abc.virtualmethod デコレーター。これにより、virtualmethod をオーバーライドしていないオブジェクトのインスタンス化でエラーが発生します。これには、次のことも必要です。 abc.ABCMeta あなたのクラスの __metaclass__.

を参照してください。 abcモジュール 詳細といくつかの例については、こちらをご覧ください。

これは一般的には行われません。通常は、実装者が指定されたメソッドをオーバーライドする必要があるという趣旨のドキュメントのみが存在します。ただし、これは、その新しさによるものかもしれません。 abc モジュール (Python 2.6 の新機能) を使用すると、このアプローチの非Python 性が認識されます。

なぜ持ってみませんか cleanup メソッドを上げるだけです NotImplementedError いつ呼ばれますか?彼らがあなたの子供のクラスを働かせたいなら、彼らは何らかの実装を導入する必要があります。

私は個人的にそれを使用したことはありませんが、私は多くの言及を見てきました ZOPEインターフェイス. 。これはあなたのタスクにとってはやり過ぎかもしれませんが、それはあなたにある程度の方向性を与えるかもしれません。そして、それはJavaの背景を持つ誰かに快適に感じるかもしれません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top