Pythonでオブジェクトの名前を取得する方法はありますか?例えば:
my_list = [x, y, z] # x, y, z have been previously defined
for bla in my_list:
print "handling object ", name(bla) # <--- what would go instead of `name`?
# do something to bla
編集:コンテキスト:
私が実際にやっているのは、コマンドラインで指定できる関数のリストを作成することです。
私が持っています:
def fun1:
pass
def fun2
pass
def fun3:
pass
fun_dict = {'fun1': fun1,
'fun2': fun2,
'fun3': fun3}
コマンドラインから関数の名前を取得し、関連する関数を呼び出したい:
func_name = parse_commandline()
fun_dict[func_name]()
そして、関数の名前を持ちたいのは、fun_dict
バグを作成する良い方法のように思えるので、関数の名前を2回書くことなく。私がやりたいことは:
fun_list = [fun1, fun2, fun3] # and I'll add more as the need arises
fun_dict = {}
[fun_dict[name(t) = t for t in fun_list] # <-- this is where I need the name function
この方法では、関数名を1回だけ記述する必要があります。
オブジェクトは必ずしもPythonで名前を持っているとは限らないため、名前を取得することはできません。オブジェクトが名前を持っている場合に__name__
属性を持つことは珍しいことではありませんが、これは標準のpythonの一部ではなく、ほとんどの組み込み型にはありません。
上記のx、y、zなどの変数を作成すると、それらの名前はオブジェクトへの「ポインター」または「参照」として機能します。オブジェクト自体は、どの名前を使用しているかを知らないため、そのオブジェクトへのすべての参照の名前を簡単に取得することはできません。
更新:ただし、関数には__name__
があります(ラムダでない限り)。この場合、次のことができます。
dict([(t.__name__, t) for t in fun_list])
同じ値を持つ変数が複数ある場合や、値が変数を持たない場合、または値が変数と同じ値をたまたま持つ可能性があるため、これは実際には不可能です。
本当にそれをしたい場合は、使用することができます
def variable_for_value(value):
for n,v in globals().items():
if v == value:
return n
return None
ただし、最初に名前を反復処理する方が良いでしょう。
my_list = ["x", "y", "z"] # x, y, z have been previously defined
for name in my_list:
print "handling variable ", name
bla = globals()[name]
# do something to bla
このワンライナーは、globals()
dictにある限り、すべてのタイプのオブジェクトに対して機能します。
def name_of_global_obj(xx):
return [objname for objname, oid in globals().items()
if id(oid)==id(xx)][0]
または、同等に:
def name_of_global_obj(xx):
for objname, oid in globals().items():
if oid is xx:
return objname
インタープリターで定義されている関数またはラムダまたはその他の関数のようなオブジェクトの名前を取得する場合は、 dill
からdill.source.getname
を使用できます。ほとんど__name__
メソッドを探しますが、特定の場合には、名前を見つける方法について他の魔法を知っています...またはa nameオブジェクト。1つの本当の名前のpythonオブジェクトの意味は何でも。
>>> from dill.source import getname
>>>
>>> def add(x,y):
... return x+y
...
>>> squared = lambda x:x**2
>>>
>>> print getname(add)
'add'
>>> print getname(squared)
'squared'
>>>
>>> class Foo(object):
... def bar(self, x):
... return x*x+x
...
>>> f = Foo()
>>>
>>> print getname(f.bar)
'bar'
>>>
>>> woohoo = squared
>>> plus = add
>>> getname(woohoo)
'squared'
>>> getname(plus)
'add'
他の人が言ったように、これは本当に難しい質問です。これに対する解決策は、「1つのサイズですべてに適合する」ものではなく、リモートでもありません。難易度(または使いやすさ)は、実際に状況によって異なります。
私はこの問題に何度か遭遇しましたが、ごく最近ではデバッグ機能の作成中にこの問題に遭遇しました。関数がいくつかの未知のオブジェクトを引数として取り、宣言された名前と内容を出力することを望みました。内容の取得はもちろん簡単ですが、宣言された名前は別の話です。
以下は、私が思いついたものの一部です。
関数の宣言された名前を含む__ name __属性を持っているため、関数の名前を決定するのは本当に簡単です。
_name_of_function = lambda x : x.__name__
def name_of_function(arg):
try:
return arg.__name__
except AttributeError:
pass`
_
例として、関数def test_function(): pass
、次に_copy_function = test_function
_、次にname_of_function(copy_function)
を作成すると、test_functionが返されます。
オブジェクトに__ name __属性があるかどうかを確認し、ある場合はそれを返します(宣言された関数のみ)。名前はglobals()
のままなので、このテストを削除してもよいことに注意してください。
Argの値をglobals()
の項目の値と比較し、最初に一致した名前を返します。 「_」で始まる名前を除外していることに注意してください。
結果は、最初に一致したオブジェクトの名前で構成されます。それ以外の場合はなしです。
_def name_of_object(arg):
# check __name__ attribute (functions)
try:
return arg.__name__
except AttributeError:
pass
for name, value in globals().items():
if value is arg and not name.startswith('_'):
return name
_
globals()
のアイテムの値と比較し、名前をリストに保存します。 「_」で始まる名前を除外していることに注意してください。結果は、リスト(複数の一致の場合)、文字列(単一の一致の場合)、それ以外の場合はなしで構成されます。もちろん、必要に応じてこの動作を調整する必要があります。
_def names_of_object(arg):
results = [n for n, v in globals().items() if v is arg and not n.startswith('_')]
return results[0] if len(results) is 1 else results if results else None
_
これについて考える別の方法があります。引数の名前を返すname()
関数があったとします。次のコードを考えます:
_def f(a):
return a
b = "x"
c = b
d = f(c)
e = [f(b), f(c), f(d)]
_
name(e[2])
は何を返す必要があり、なぜですか?
そして、関数の名前を持ちたいのは、
fun_dict
バグを作成する良い方法のように思えるので、関数の名前を2回書くことなく。
この目的のために、素晴らしい getattr
関数があり、既知の名前でオブジェクトを取得できます。たとえば、次のことができます。
funcs.py:
def func1(): pass
def func2(): pass
main.py:
import funcs
option = command_line_option()
getattr(funcs, option)()
逆辞書を使用します。
fun_dict = {'fun1': fun1,
'fun2': fun2,
'fun3': fun3}
r_dict = dict(Zip(fun_dict.values(), fun_dict.keys()))
逆辞書は、各関数参照をfun_dictで指定した正確な名前にマッピングします。これは、関数を定義したときに使用した名前である場合とそうでない場合があります。そして、この手法は整数を含む他のオブジェクトに一般化します。
余計な楽しみと狂気のために、同じ辞書に順方向と逆方向の値を保存できます。文字列を文字列にマッピングする場合はそうしませんが、関数参照や文字列のようなことをしているなら、それはあまり気になりません。
前述のように、オブジェクトは一般にどの変数にバインドされているかを知らないので、def
で定義された関数には___name__
_属性(def
で使用される名前)の名前があります。また、関数が(あなたの例のように)同じモジュールで定義されている場合、globals()
には必要な辞書のスーパーセットが含まれます。
_def fun1:
pass
def fun2:
pass
def fun3:
pass
fun_dict = {}
for f in [fun1, fun2, fun3]:
fun_dict[f.__name__] = f
_
通常、このようなことをしたい場合は、これらの関数をすべて保持するクラスを作成し、_cmd_
_などの明確なプレフィックスを付けて名前を付けます。次に、コマンドから文字列を取得し、_cmd_
_プレフィックスが付いたクラスからその属性を取得しようとします。これで、新しい関数/メソッドをクラスに追加するだけで、呼び出し元が使用できるようになりました。また、ドキュメント文字列を使用して、ヘルプテキストを自動的に作成できます。
他の回答で説明したように、モジュール内のglobals()
および通常の関数を使用して同じアプローチを実行し、要求にさらに一致させることができる場合があります。
このようなもの:
_class Tasks:
def cmd_doit(self):
# do it here
func_name = parse_commandline()
try:
func = getattr('cmd_' + func_name, Tasks())
except AttributeError:
# bad command: exit or whatever
func()
_
同じ質問に疑問を抱きながらこのページにぶつかりました。
他の人が指摘したように、関数の名前を決定するために関数から__name__
属性を取得するだけで十分です。 __name__
、つまりbasestringインスタンス、int、longsなどのベース/プリミティブオブジェクトを決定するための適切な方法を持たないオブジェクトでは、やや複雑です。
簡単に言えば、おそらくinspectモジュールを使用して、どのモジュールであるかを経験に基づいた推測をすることができますが、正しいフレームを見つけるには、スタックでどのフレームで作業しているのかを知る必要があります。しかし、これがeval/exec'edコードを処理しようとするのがどれほど楽しいか想像するのは嫌です。
% python2 whats_my_name_again.py
needle => ''b''
['a', 'b']
[]
needle => '<function foo at 0x289d08ec>'
['c']
['foo']
needle => '<function bar at 0x289d0bfc>'
['f', 'bar']
[]
needle => '<__main__.a_class instance at 0x289d3aac>'
['e', 'd']
[]
needle => '<function bar at 0x289d0bfc>'
['f', 'bar']
[]
%
whats_my_name_again.py:
#!/usr/bin/env python
import inspect
class a_class:
def __init__(self):
pass
def foo():
def bar():
pass
a = 'b'
b = 'b'
c = foo
d = a_class()
e = d
f = bar
#print('globals', inspect.stack()[0][0].f_globals)
#print('locals', inspect.stack()[0][0].f_locals)
assert(inspect.stack()[0][0].f_globals == globals())
assert(inspect.stack()[0][0].f_locals == locals())
in_a_haystack = lambda: value == needle and key != 'needle'
for needle in (a, foo, bar, d, f, ):
print("needle => '%r'" % (needle, ))
print([key for key, value in locals().iteritems() if in_a_haystack()])
print([key for key, value in globals().iteritems() if in_a_haystack()])
foo()
変数名はglobals()およびlocals()の辞書にあります。しかし、それらはあなたが上で探しているものをあなたに与えません。 「bla」には、変数ではなく、my_listの各項目の値が含まれます。
ここに私の答えがあり、globals()。items()も使用しています
def get_name_of_obj(obj, except_Word = ""):
for name, item in globals().items():
if item == obj and name != except_Word:
return name
Forループで使用されているWordをフィルターで除外するため、except_Wordを追加しました。追加しなかった場合、forループのキーワードはこの関数を混乱させる可能性があります。次の場合の「each_item」のようなキーワードは、ループの実行内容によっては関数の結果に表示される場合があります。
例えば。
for each_item in [objA, objB, objC]:
get_name_of_obj(obj, "each_item")
例えば。
>>> objA = [1, 2, 3]
>>> objB = ('a', {'b':'thi is B'}, 'c')
>>> for each_item in [objA, objB]:
... get_name_of_obj(each_item)
...
'objA'
'objB'
>>>
>>>
>>> for each_item in [objA, objB]:
... get_name_of_obj(each_item)
...
'objA'
'objB'
>>>
>>>
>>> objC = [{'a1':'a2'}]
>>>
>>> for item in [objA, objB, objC]:
... get_name_of_obj(item)
...
'objA'
'item' <<<<<<<<<< --------- this is no good
'item'
>>> for item in [objA, objB]:
... get_name_of_obj(item)
...
'objA'
'item' <<<<<<<<--------this is no good
>>>
>>> for item in [objA, objB, objC]:
... get_name_of_obj(item, "item")
...
'objA'
'objB' <<<<<<<<<<--------- now it's ok
'objC'
>>>
これが役立つことを願っています。
Pythonには、名前空間と呼ばれるハッシュマップ内のオブジェクトにマップされる名前があります。いつでも、名前は常に1つのオブジェクトを参照しますが、1つのオブジェクトは任意の数の名前で参照できます。名前を指定すると、その名前が参照する単一のオブジェクトをハッシュマップが検索することは非常に効率的です。ただし、前述のように複数の名前で参照できるobjectを指定すると、それを参照する名前を検索する効率的な方法がありません。あなたがしなければならないことは、名前空間内のすべての名前を反復処理し、それぞれを個別にチェックし、それが与えられたオブジェクトにマップされるかどうかを確認することです。これはリスト内包表記で簡単にできます:
_[k for k,v in locals().items() if v is myobj]
_
これは、現在オブジェクトmyobj
にマップされているすべてのローカル「変数」の名前を含む文字列のリストに評価されます。
_>>> a = 1
>>> this_is_also_a = a
>>> this_is_a = a
>>> b = "ligma"
>>> c = [2,3, 534]
>>> [k for k,v in locals().items() if v is a]
['a', 'this_is_also_a', 'this_is_a']
_
もちろん、locals()
は、特定のオブジェクトを指す名前を検索するdict
で置き換えることができます。明らかに、この検索は、非常に大きな名前空間全体を横断する必要があるため、非常に遅いことがあります。
class
を定義し、Unicodeプライベート関数を追加してclass
を挿入します
class example:
def __init__(self, name):
self.name = name
def __unicode__(self):
return self.name
もちろん、オブジェクトの名前であるself.name
という追加の変数を追加する必要があります。