27

オブジェクトにメンバーがあるかどうかを定期的に確認したいと思います。例として、関数内でのシングルトンの作成があります。そのために、次hasattrのように使用できます。

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance

しかし、これを行うこともできます:

class Foo(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Foo()
            return self.instance

ある方法が他の方法よりも優れていますか?

編集:追加...しかし、問題はシングルトンの作成方法ではなく@classmethod、オブジェクト内のメンバーの存在を確認する方法であることに注意してください。

編集:その例では、典型的な使用法は次のようになります。

s = Foo.singleton()

次にs、タイプ のオブジェクトでFoo、毎回同じです。そして、通常、メソッドは何度も呼び出されます。

4

5 に答える 5

22

これらは 2 つの異なる方法論です。№1 は LBYL (ジャンプする前に確認) であり、№2 は EAFP (許可よりも許しを求める方が簡単) です。

Pythonistas は通常、EAFP の方が優れていると提案し、「プロセスがファイルをテストしてから自分で作成しようとするまでの間にファイルを作成するとどうなるか?」というような議論をします。この議論はここでは当てはまりませんが、一般的な考え方です。例外は、あまりにも例外的なものとして扱われるべきではありません。

あなたの場合、パフォーマンスに関して—CPythonでは例外マネージャー(tryキーワード)の設定は非常に安価ですが、例外の作成(raiseキーワードと内部例外の作成)は比較的高価であるため—方法№2を使用すると、例外は1回だけ発生します; その後、プロパティを使用するだけです。

于 2008-10-15T12:28:11.233 に答える
10

私はちょうど時間を測定しようとしました:

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance



class Bar(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Bar()
            return self.instance



from time import time

n = 1000000
foo = [Foo() for i in xrange(0,n)]
bar = [Bar() for i in xrange(0,n)]

print "Objs created."
print


for times in xrange(1,4):
    t = time()
    for d in foo: d.singleton()
    print "#%d Foo pass in %f" % (times, time()-t)

    t = time()
    for d in bar: d.singleton()
    print "#%d Bar pass in %f" % (times, time()-t)

    print

私のマシンで:

Objs created.

#1 Foo pass in 1.719000
#1 Bar pass in 1.140000

#2 Foo pass in 1.750000
#2 Bar pass in 1.187000

#3 Foo pass in 1.797000
#3 Bar pass in 1.203000

try/except の方が速いようです。とにかく、場合によっては、このテストは非常に単純だったので、もっと複雑なテストが必要になるかもしれません。

于 2008-10-15T12:15:54.300 に答える
5

例外は、まあ、非定型の条件をモデル化する必要があるため、どのケースが「典型的」であるかによって異なります。そのため、典型的なケースとしてinstance属性が存在する必要がある場合は、2 番目のコード スタイルを使用します。持っていないことinstanceが、持っているのと同じくらい典型的な場合instanceは、最初のスタイルを使用してください。

シングルトンを作成する特定のケースでは、最初の時間にシングルトンを作成するのが典型的なユースケースであるため、最初のスタイルを使用する傾向があります。:-)

于 2008-10-15T10:59:22.283 に答える
1

それを使用する方法で少しオフトピック。シングルトンは過大評価されており、「共有状態」メソッドは同様に効果的であり、ほとんどの場合、Python では非常にクリーンです。次に例を示します。

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state
    # and whatever else you want in your class -- that's all!

今あなたがするたびに:

obj = Borg()

同じ情報を持っているか、多少同じインスタンスになります。

于 2008-10-15T12:45:28.327 に答える
0

私はクリスに同意しなければなりません。実際に必要になるまで最適化しないでください。妥当なプログラムでは、存在のチェックがボトルネックになるとは思えません。

これを行う方法としてhttp://code.activestate.com/recipes/52558/も見ました。そのコードのコメントを外したコピー (「スパム」は、クラス インターフェイスが持つランダムなメソッドです):

class Singleton:
    class __impl:
        def spam(self):
            return id(self)
    __instance = None
    def __init__(self):
        if Singleton.__instance is None:
            Singleton.__instance = Singleton.__impl()
        self.__dict__['_Singleton__instance'] = Singleton.__instance
    def __getattr__(self, attr):
        return getattr(self.__instance, attr)
    def __setattr__(self, attr, value):
        return setattr(self.__instance, attr, value)
于 2008-10-15T12:27:14.807 に答える