属性の存在を確認するのに最適な方法はどれですか?[重複しています]。
質問
属性の存在を確認する方法として、どちらが良いでしょうか?
Jarret Hardie はこのように回答しています。
if hasattr(a, 'property'):
a.property
このような方法もあるのですね。
if 'property' in a.__dict__:
a.property
あるアプローチは通常、他のアプローチよりも多く使われているのでしょうか?
どのように解決するのですか?
ベストな方法はありません。 なぜなら、ある属性が存在するかどうかを確認するためだけでは決してなく、それは常に何らかの大きなプログラムの一部だからです。 いくつかの正しい方法と、1 つの顕著な間違った方法があります。
間違った方法
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
出力します。
a.__dict__の'prop' = False hasattr(a, 'prop') = True a.prop = 3
たいていの場合、あなたは
__dict__
. これは特別なことをするための特別な属性であり、属性が存在するかどうかを確認することはかなり平凡なことです。
EAFPの方法
Pythonでよく使われる慣用句に "easy to ask for forgiveness than permission" 略して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)
オプションモジュールのインポートも...
try:
import readline
except ImportError:
pass
LBYL流
この
hasattr
という方法も、もちろん有効です。 このテクニックは、quot;look before you leap"、略してLBYLと呼ばれています。
# Cached attribute
if not hasattr(self, 'big_object'):
big_object = CreateBigObject()
self.big_object = CreateBigObject()
big_object.do_something()
(この
hasattr
は Python 3.2 より前のバージョンでは例外に関して奇妙な振る舞いをします -- 捕まえるべきでない例外を捕らえてしまいます -- が、そのような例外はまずないので、これはおそらく無関係でしょう。 しかし、そのような例外が発生する可能性は低いので、これはおそらく無関係でしょう。
hasattr
のテクニックは
try/except
の方が遅いのですが、気にするほど頻繁に呼び出すわけではありませんし、その差はそれほど大きくありません。 最後に
hasattr
はアトミックではないので
AttributeError
を投げるかもしれません。しかし、これはあまり考えにくいシナリオで、スレッドの周りではとにかく慎重になる必要があります。 これら 3 つの違いのいずれも、心配するほどのものだとは思いません)。
使用方法
hasattr
よりもはるかに簡単です。
try/except
よりも単純で、属性が存在するかどうかを知る必要があるだけです。 私にとっての大きな問題は、PythonプログラマーとしてEAFP手法を読むのに慣れているため、LBYL手法が"奇妙"に見えるということです。 もし上記の例を書き直して
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の方法
デフォルト値が必要なだけなら
getattr
の短いバージョンです。
try/except
.
x = getattr(self, 'x', default_value)
デフォルト値を構成するのが高価な場合、次のようなものになります。
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
まとめ
内部的には
getattr
と
hasattr
ビルトインは、単に
try/except
のテクニックを使うだけです (C 言語で書かれたものを除く)。 つまり、重要なところではすべて同じように動作し、正しいものを選ぶのは状況やスタイルの問題によるのです。
は
try/except
EAFP のコードは常に一部のプログラマを不愉快にさせるでしょうし、また
hasattr/getattr
LBYLコードは他のプログラマーを苛立たせるでしょう。 どちらも正しいし、どちらかを選ばなければならない本当に説得力のある理由もないことが多いのです。 (しかし、他のプログラマは、属性が未定義であることが正常であると考えることにうんざりしていますし、一部のプログラマは Python で未定義の属性を持つことが可能であることに恐怖を感じています)。
関連
-
[解決済み] 文字列リテラルの前にある'b'文字は何を意味するのでしょうか?
-
[解決済み] for'ループでインデックスにアクセスする?
-
[解決済み] 最小限の驚き」と「変更可能なデフォルトの引数
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み] 文字列が空かどうかを確認する方法は?
-
[解決済み] Pythonで型をチェックする標準的な方法は何ですか?
-
[解決済み] Pythonでシングルトンを作成する
-
[解決済み] NaN値をチェックするにはどうすればよいですか?
-
[解決済み] mixinとは何か、なぜ有用なのか?
-
[解決済み] SQLAlchemy - テーブルのリストを取得する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Pythonでオブジェクトが属性を持つかどうかを知る方法
-
[解決済み] Pandasのデータフレームでタプルの列を分割するにはどうしたらいいですか?
-
[解決済み] Pythonのマルチプロセッシングプールimap_unorderedの呼び出しの進捗を表示しますか?
-
[解決済み] Flaskで1時間ごとに関数を実行するようにスケジュールするには?
-
[解決済み] 小数点以下1桁を取得する[重複]。
-
[解決済み] ファブリック経由でデプロイユーザとしてvirtualenvを有効化する
-
[解決済み] Cythonのコードを含むPythonパッケージはどのように構成すればよいのでしょうか?
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] PythonのRequestsモジュールを使ってWebサイトに "ログイン "するには?
-
[解決済み] hasattr() vs try-except ブロックによる存在しない属性の処理