1

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

渡すオブジェクトはすべて同じ基本クラスを持っています(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()メソッドを抽象化して、子が実装を提供する必要があるこれらすべてのオブジェクトに対して同じ親クラスを持つことができるよう にするにはどうすればよいですか?

おそらくもっと重要なのは、これは「pythonic」ですか?このルートに行くべきですか、それともダックタイピングだけに頼るべきですか?私のバックグラウンドはJavaで、Pythonのやり方を学ぼうとしています。

ありがとう!

4

5 に答える 5

4

abc モジュールを使用します。具体的には、基本クラスのメタクラスをに設定し、メソッドでデコレータABCMetaを使用します。@abstractmethodcleanup

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

于 2010-09-24T01:41:57.163 に答える
1

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

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

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

于 2010-09-24T01:42:26.177 に答える
1

メソッドが呼び出されたときに、cleanupメソッドを発生させてみませんか?NotImplementedError子供たちのクラスを機能させたい場合は、何らかの実装を行う必要があります。

于 2010-09-24T01:46:17.073 に答える
0

利用可能な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)はメタクラスが使用されるものに解決されるためdb.Model、Googleのコードを踏むことはありません。また、何も壊さないように、 _abstract_methods_Googleのメソッドに渡される前にクラスディクショナリからポップアウトします。__new__その名前の属性がすでにある場合db.Modelは、それを別の名前に変更する必要があります。

于 2010-09-24T02:23:28.873 に答える
0

私はそれを個人的に使用したことはありませんが、Zopeインターフェースへの参照をたくさん見ました。これはあなたの仕事にとってやり過ぎかもしれませんが、それはあなたにいくらかの方向性を与えるかもしれません。そして、Javaのバックグラウンドを持つ人にとっては快適に感じるかもしれません。

于 2010-09-25T04:50:28.907 に答える