web-dev-qa-db-ja.com

python)で動的属性を取得する

私は、3つの異なる方法で名前を付けることができるpseudoまたはspecial属性を持つオブジェクトを持っています(注:オブジェクトを生成するコードを制御しません)

属性の値(設定されているものによって異なります)はまったく同じであり、さらに処理するためにそれを取得する必要があるため、データのソースに応じて、次のようにすることができます。

>>> obj.a
'value'
>>> obj.b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'b'
>>> obj.c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'c'

または

>>> obj.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'a'
>>> obj.b
'value'
>>> obj.c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'c'

または

>>> obj.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'a'
>>> obj.b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Obj instance has no attribute 'b'
 >>> obj.c
'value'

'value'を取得することに興味がありますが、残念ながら__dict__プロパティはそのオブジェクトに存在しません。したがって、その値を取得するために私がやったことは、getattr呼び出しをたくさん行うことでした。可能性が3つだけであると仮定すると、コードは次のようになります。

>>> g = lambda o, l: getattr(o, l[0], getattr(o, l[1], getattr(o, l[2], None)))
>>> g(obj, ('a', 'b', 'c'))
'value'

さて、これにもっと良い方法があるかどうか知りたいですか?私は自分がやったことを100%確信しているので:)

前もって感謝します

19
rhormaza

どうですか:

for name in 'a', 'b', 'c':
    try:
        thing = getattr(obj, name)
    except AttributeError:
        pass
    else:
        break
38
wim

これには、任意の数のアイテムを処理できるという利点があります。

 def getfirstattr(obj, *attrs):
     return next((getattr(obj, attr) for attr in attrs 
                  if hasattr(obj, attr)), None)

これにはveryマイナーな欠点があり、最終値に対して2つのルックアップを実行します。1回は属性が存在することを確認するため、もう1回は実際に値を取得するためです。これは、ネストされたジェネレータ式を使用することで回避できます。

 def getfirstattr(obj, *attrs):
     return next((val for val in (getattr(obj, attr, None) for attr in attrs)
                  if val is not None), None)

しかし、私はそれが大したことだとは本当に感じていません。ジェネレータ式は、ダブルルックアップを使用した場合でも、単純な古いループよりも高速になる可能性があります。

2
kindall

Dirを使用すると、基本的に同じものが得られると思います__dict__通常は.。

targetValue = "value"
for k in dir(obj):
    if getattr(obj,k) == targetValue:
       print "%s=%s"%(k,targetValue)

何かのようなもの

>>> class x:
...    a = "value"
...
>>> dir(x)
['__doc__', '__module__', 'a']
>>> X = x()
>>> dir(X)
['__doc__', '__module__', 'a']
>>> for k in dir(X):
...     if getattr(X,k) == "value":
...        print "%s=%s"%(k,getattr(X,k))
...
a=value
>>>
0
Joran Beasley

オブジェクトの構造によっては、これを行うためのより良い方法があるかもしれませんが、他に何も知らないので、任意の数の引数で機能することを除いて、現在のソリューションとまったく同じように機能する再帰ソリューションを次に示します。

g = lambda o, l: getattr(o, l[0], g(o, l[1:])) if l else None
0
Andrew Clark