Pythonでのメンバーの存在の確認
-
03-07-2019 - |
質問
オブジェクトにメンバーがあるかどうかを定期的にチェックしたい。例は、関数内のシングルトンの作成です。そのためには、次のように 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
1つの方法は他の方法より優れていますか?
編集: @classmethod
を追加しました...しかし、質問はシングルトンを作る方法ではなく、チェックする方法について ではないことに注意してくださいオブジェクト内のメンバーの存在。
編集:その例の典型的な使用法は次のとおりです。
s = Foo.singleton()
その後、 s
は、毎回同じタイプの Foo
のオブジェクトです。そして、通常、メソッドは何度も呼び出されます。
解決
これらは2つの異なる方法論です。№ 1はLBYL(ジャンプする前に見てください)および№ 2はEAFP(許可よりも許しを求める方が簡単です)。
Pythonistasは通常、EAFPの方が優れていることを提案します。引数は"プロセスをテストしてから自分で作成するまでの間にプロセスがファイルを作成するとどうなりますか?この議論はここでは当てはまりませんが、一般的な考え方です。例外を too 例外として扱うべきではありません。
あなたの場合のパフォーマンスについて—例外の作成中( try
キーワード)の例外マネージャーのセットアップはCPythonで非常に安価であるため( raise
キーワードおよび内部例外の作成)は比較的高価です—メソッド№ 2を使用すると、例外は1回だけ発生します。その後、プロパティを使用するだけです。
他のヒント
時間を測定しようとしました:
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の方が速いようです。私にとっても読みやすいようです。とにかく場合によって異なりますが、このテストは非常に簡単だったので、もっと複雑なテストが必要になるかもしれません。
例外は、例外的な状態をモデル化する必要があるため、どのケースが「典型的な」かによって異なります。したがって、典型的なケースが instance
属性が存在する必要がある場合、2番目のコードスタイルを使用します。 instance
を持たないことが instance
を持っているのと同じくらい一般的な場合、最初のスタイルを使用します。
シングルトンを作成する特定のケースでは、最初にシングルトンを作成するのが典型的なユースケースであるため、最初のスタイルを使用する傾向があります。 :-)
それを使用する方法で少しトピックから外れています。シングルトンは過大評価されており、「共有状態」はメソッドは同様に効果的で、ほとんどの場合、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()
同じ情報を持つか、または多少同じインスタンスになります。
クリスに同意しなければなりません。実際に最適化する必要があるまで最適化しないでください。存在を確認することが、妥当なプログラムのボトルネックになることは本当に疑わしい。
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)