属性の有無を確認するには、どちらの方法が適していますか?属性の存在を確認する最良の方法はどれですか?
if 'property' in a.__dict__:
a.property
は、一つのアプローチ一般的に他の人よりも多く使用されている:?私はそれがこの方法をも行うことができることがわかり
if hasattr(a, 'property'):
a.property
:この回答を提供
属性の有無を確認するには、どちらの方法が適していますか?属性の存在を確認する最良の方法はどれですか?
if 'property' in a.__dict__:
a.property
は、一つのアプローチ一般的に他の人よりも多く使用されている:?私はそれがこの方法をも行うことができることがわかり
if hasattr(a, 'property'):
a.property
:この回答を提供
属性が存在するかどうかを確認するだけではないので、「最良」の方法はありません。です。それはいつもより大きなプログラムの一部です。いくつかの正しい方法と顕著な方法があります。
if 'property' in a.__dict__:
a.property
は、この技術の失敗を示したデモンストレーションです:
class A(object):
@property
def prop(self):
return 3
a = A()
print "'prop' in a.__dict__ =", 'prop' in a.__dict__
print "hasattr(a, 'prop') =", hasattr(a, 'prop')
print "a.prop =", a.prop
は出力:
'prop' in a.__dict__ = False hasattr(a, 'prop') = True a.prop = 3
ほとんどの時間、あなたはしたくありません__dict__
をつぶす。それは特別なことを行うための特別な属性であり、属性が存在するかどうかを確認することはかなり平凡です。 Pythonで
共通イディオムは略して「許可よりも許しを求めるしやすい」、またはEAFPです。このイディオムを使用する多くのPythonコードが、属性の存在をチェックするためだけでなく、表示されます。
# Cached attribute
try:
big_object = self.big_object
# or getattr(self, 'big_object')
except AttributeError:
# Creating the Big Object takes five days
# and three hundred pounds of over-ripe melons.
big_object = CreateBigObject()
self.big_object = big_object
big_object.do_something()
これは、存在しない可能性のあるファイルを開く場合とまったく同じイディオムであることに注意してください。
try:
f = open('some_file', 'r')
except IOError as ex:
if ex.errno != errno.ENOENT:
raise
# it doesn't exist
else:
# it does and it's open
また、文字列を整数に変換する場合。
でも... try:
i = int(s)
except ValueError:
print "Not an integer! Please try again."
sys.exit(1)
LBYLの道
hasattr
方法は、当然のことながら、あまりにも動作します。この技法は、「あなたが飛躍する前に見る」、または略してLBYLと呼ばれています。
# Cached attribute
if not hasattr(self, 'big_object'):
big_object = CreateBigObject()
self.big_object = CreateBigObject()
big_object.do_something()
(hasattr
組み込みが実際に例外に関して3.2より前のバージョンのPythonで動作がおかしい - それはいけないという例外をキャッチします - しかし、そのような例外はほとんどありませんので、これは、おそらく無関係です。 hasattr
のテクニックもtry/except
よりも遅いですが、それほど頻繁に呼び出すことはなく、違いはあまり大きくありません。最後にhasattr
はアトミックではないので、別のスレッドが属性を削除するとAttributeError
とにかくスレッドに関しては非常に注意する必要があります。私はこれらの3つの違いのいずれかを心配する価値はないと考えています。)
hasattr
を使用すると、属性が存在するかどうかを知る必要がある限り、try/except
よりはるかに簡単です。私の大きな問題は、LBYLのテクニックが "奇妙"に見えるということです。なぜなら、Pythonのプログラマーとして、私はEAFPテクニックの読み方に慣れているからです。上記の例をLBYL
スタイルを使用するように書き直すと、不器用、間違った、または書きにくいいずれかのコードが得られます。
# Seems rather fragile...
if re.match('^(:?0|-?[1-9][0-9]*)$', s):
i = int(s)
else:
print "Not an integer! Please try again."
sys.exit(1)
そしてLBYLは時々完全に間違っています:
if os.path.isfile('some_file'):
# At this point, some other program could
# delete some_file...
f = open('some_file', 'r')
オプションのモジュールをインポートするためLBYL関数を書きたい場合は、私のゲストも...関数は、全モンスターになるように聞こえます。あなただけのデフォルト値が必要な場合は
、getattr
はtry/except
の短いバージョンです。
x = getattr(self, 'attr', None)
if x is None:
x = CreateDefaultValue()
self.attr = x
それともNone
が可能な値であれば、
sentinel = object()
x = getattr(self, 'attr', sentinel)
if x is sentinel:
x = CreateDefaultValue()
self.attr = x
x = getattr(self, 'x', default_value)
、あなたはこのようなものになってしまいます
内部的には、getattr
およびhasattr
ビルトインtry/except
テクニックを使用してください(C言語で書かれている場合を除く)。だから、彼らはみな同じように振る舞い、正しいものを選ぶのは状況とスタイルの問題によるものです。
try/except
EAFPコードは、常に一部のプログラマーに間違ったやり方をぶつけ、hasattr/getattr
LBYLコードは他のプログラマーに影響を与えます。彼らはどちらも正しいですし、しばしばどちらかを選ぶ本当の理由がありません。 (しかし、他のプログラマは、あなたはそれが通常の属性が未定義であるために検討することにうんざりしている、といくつかのプログラマが、それはPythonで未定義の属性を持つことも可能だと恐怖です。)
おそらく 'try ... except'は' x'が 'x.attr'という属性を持つことがほとんどいつも期待される方が良いでしょう。 (例外は本当に例外的です。) –
私はほとんどの場合、 'try ... except'を個人的に使うと、' hasattr'メソッドは私の口に悪い味を残します。 –
@Dietrich Epp:上記の 'try/except'のような例外を隠す可能性のあるコードは、' hasattr() 'より明らかに悪いです。 – jfs
hasattr()
は*方法です。
a.__dict__
は醜いので、多くの場合は機能しません。 hasattr()
は実際に属性を取得しようとしてAttributeError
を内部的にキャッチしますので、カスタム__getattr__()
メソッドを定義しても機能します。属性を要求しないようにするに
は二回getattr()
のための第三引数を使用することができる:
not_exist = object()
# ...
attr = getattr(obj, 'attr', not_exist)
if attr is not_exist:
do_something_else()
else:
do_something(attr)
それはあなたのケースでは、より適切である場合は、だけではなく、not_exist
センチネルのデフォルト値を使用することができます。
私は好きではないtry: do_something(x.attr) \n except AttributeError: ..
それはAttributeError
do_something()
内部の機能を隠すことがあります。
*Before Python 3.1 hasattr()
suppressed all exceptions(だけではなくAttributeError
)それが望ましくない場合getattr()
を使用する必要があります。
hasattr()
は、これを行うにはPythonの方法です。それを学んで、それを愛してください。
if varName in locals() or in globals():
do_something()
else:
do_something_else()
は私が個人的に何かを確認するために、例外をキャッチするために嫌い:
他の可能な方法は、変数名がlocals()
かglobals()
であるかどうかを確認することです。それは見て、醜い感じ。
s = "84984x"
try:
int(s)
do_something(s)
except ValueError:
do_something_else(s)
の代わりに優しくs.isdigit()
を使用して:文字列が数字だけそのように含まれている場合は、チェックと同じです。 Eww。
'int' /' isdigit'バージョンは重要な方法です。 'int'バージョンは負の数を許します。私は、負の数に対しては正しく動作し、無関係な先行ゼロを持つ数字は拒否します(Pythonのように)。 –
非常に古い質問ですが、本当に良い答えが必要です。短いプログラムでさえ、私はカスタム関数を使うといいでしょう!
例を示します。それはすべてのアプリケーションには完璧ではありませんが、私のために、無数のAPIからの応答を解析し、Djangoを使用しています。誰もが自分の要求に合わせて修正するのは簡単です。
from django.core.exceptions import ObjectDoesNotExist
from functools import reduce
class MultipleObjectsReturned(Exception):
pass
def get_attr(obj, attr, default, asString=False, silent=True):
"""
Gets any attribute of obj.
Recursively get attributes by separating attribute names with the .-character.
Calls the last attribute if it's a function.
Usage: get_attr(obj, 'x.y.z', None)
"""
try:
attr = reduce(getattr, attr.split("."), obj)
if hasattr(attr, '__call__'):
attr = attr()
if attr is None:
return default
if isinstance(attr, list):
if len(attr) > 1:
logger.debug("Found multiple attributes: " + str(attr))
raise MultipleObjectsReturned("Expected a single attribute")
else:
return str(attr[0]) if asString else attr[0]
else:
return str(attr) if asString else attr
except AttributeError:
if not silent:
raise
return default
except ObjectDoesNotExist:
if not silent:
raise
return default
あなたの2番目のオプションは間違っていますが、とにかく質問に答えた[second answer](http://stackoverflow.com/a/610923/1132524)です。 –