私は最近、hasattrについていくつかの ツイート と Pythonドキュメント を読んでいます。
hasattr(オブジェクト、名前)
引数はオブジェクトと文字列です。文字列がオブジェクトの属性の1つの名前である場合はTrueになり、そうでない場合はFalseになります。 (これは、getattr(object、name)を呼び出して、AttributeErrorが発生するかどうかを確認することで実装されます。)
Pythonには、私が通常同意する許可よりも許しを求める方が簡単であるというモットーがあります。
この場合、私は本当に単純なpythonコード:
import timeit
definition="""\
class A(object):
a = 1
a = A()
"""
stm="""\
hasattr(a, 'a')
"""
print timeit.timeit(stmt=stm, setup=definition, number=10000000)
stm="""\
getattr(a, 'a')
"""
print timeit.timeit(stmt=stm, setup=definition, number=10000000)
結果:
$ python test.py
hasattr(a, 'a')
1.26515984535
getattr(a, 'a')
1.32518696785
属性が存在せず、getattrとhasattrの差が大きい場合にどうなるかについても試しました。つまり、これまで見てきたことは、getattrはhasattrよりも遅いということですが、ドキュメントではgetattrを呼び出すと書かれています。
hasattr と getattr のCPython実装を検索しましたが、どちらも次の関数を呼び出しているようです。
v = PyObject_GetAttr(v, name);
しかし、getattrにはhasattrよりも多くの定型文があり、おそらく遅くなります。
ドキュメントでhasattrがgetattrを呼び出すと言っている理由を誰かが知っていますか?実際にはパフォーマンスが原因ではないのに、hasattrの代わりにgetattrを使用するようにユーザーに勧めているようです。それがよりパイソン的であるという理由だけですか?
たぶん私は私のテストで何か間違ったことをしています:)
ありがとう、
ラウル
ドキュメントは奨励していません、ドキュメントはただ明白を述べています。 hasattr
はそのように実装されており、プロパティゲッターからAttributeError
をスローすると、属性が存在しないように見せることができます。これは重要な詳細であり、それがドキュメントに明示的に記載されている理由です。たとえば、次のコードについて考えてみます。
_class Spam(object):
sausages = False
@property
def eggs(self):
if self.sausages:
return 42
raise AttributeError("No eggs without sausages")
@property
def invalid(self):
return self.foobar
spam = Spam()
print(hasattr(Spam, 'eggs'))
print(hasattr(spam, 'eggs'))
spam.sausages = True
print(hasattr(spam, 'eggs'))
print(hasattr(spam, 'invalid'))
_
結果は
_True
False
True
False
_
つまり、Spam
クラスにはeggs
のプロパティ記述子がありますが、ゲッターは_not self.sausages
_の場合にAttributeError
を発生させるため、そのクラスのインスタンスは「hasattr
"eggs
。
それ以外は、hasattr
は次の場合にのみ使用してください値は必要ありません;値が必要な場合は、2つの引数を指定してgetattr
を使用し、例外または3つの引数をキャッチします。3番目は適切なデフォルト値です。
getattr()
(2.7.9)を使用した結果:
_>>> spam = Spam()
>>> print(getattr(Spam, 'eggs'))
<property object at 0x01E2A570>
>>> print(getattr(spam, 'eggs'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in eggs
AttributeError: No eggs without sausages
>>> spam.sausages = True
>>> print(getattr(spam, 'eggs'))
42
>>> print(getattr(spam, 'invalid'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in invalid
AttributeError: 'Spam' object has no attribute 'invalid'
>>>
_
hasattr
は例外を飲み込むことに問題があるようです(少なくとも in Python 2.7 ))、おそらく修正されるまでそれから離れた方が良いでしょう。
たとえば、 次のコード :
>>> class Foo(object):
... @property
... def my_attr(self):
... raise ValueError('nope, nope, nope')
...
>>> bar = Foo()
>>> bar.my_attr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_attr
ValueError: nope, nope, nope
>>> hasattr(Foo, 'my_attr')
True
>>> hasattr(bar, 'my_attr')
False
>>> getattr(bar, 'my_attr', None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in my_attr
ValueError: nope, nope, nope
>>>