45

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]()

また、関数の名前を付けたいのは、関数の名前を2回記述せずに作成したいからです。これはfun_dict、バグを作成するための良い方法のように思われるためです。私がやりたいことは:

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

このように、私は関数名を一度だけ書く必要があります。

4

17 に答える 17

51

Pythonでは、オブジェクトに必ずしも名前が付いているとは限らないため、名前を取得することはできません。

オブジェクトに名前がある場合に属性を持つことは珍しいことで__name__はありませんが、これは標準のPythonの一部ではなく、ほとんどの組み込み型には名前がありません。

上記のように変数を作成すると、x, y, zそれらの名前はオブジェクトへの「ポインタ」または「参照」として機能します。オブジェクト自体は、使用している名前を認識しておらず、そのオブジェクトへのすべての参照の名前を簡単に取得することはできません(あるとしても)。

更新:ただし、関数には(ラムダ__name__でない限り)があります。その場合、次のことができます。

dict([(t.__name__, t) for t in fun_list])
于 2009-10-08T14:58:40.737 に答える
14

同じ値を持つ複数の変数が存在する可能性があるか、値に変数がない可能性があるか、値が偶然に変数と同じ値を持つ可能性があるため、これは実際には不可能です。

あなたが本当にそれをしたいのなら、あなたは使うことができます

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

 

于 2009-10-08T15:01:40.137 に答える
12

このワンライナーは、すべてのタイプのオブジェクトに対して、それらが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
于 2013-04-22T03:53:40.160 に答える
8

インタプリタで定義されている関数やラムダ、またはその他の関数のようなオブジェクトの名前を取得する場合は、dill.source.getnameからを使用できますdill。それはほとんど__name__メソッドを探しますが、場合によっては、名前やオブジェクトの名前を見つける方法について他の魔法を知っています。意味が何であれ、Pythonオブジェクトの1つの本当の名前を見つけることについて議論したくありません。

>>> 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'
于 2014-01-24T18:30:51.487 に答える
5

他の人が言っているように、これは本当にトリッキーな質問です。これに対する解決策は、「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、then copy_function = test_function、thenを作成すると、 test_functionname_of_function(copy_function)が返されます。

最初に一致するオブジェクト名を返す

  1. オブジェクトに__name__属性があるかどうかを確認し、ある場合はそれを返します(宣言された関数のみ)。名前はまだであるため、このテストを削除できることに注意してくださいglobals()

  2. 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

一致するすべてのオブジェクト名を返します

  • argの値を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
于 2015-05-03T21:30:03.500 に答える
2

これについて考える別の方法があります。name()引数の名前を返す関数があったとします。次のコードが与えられます:

def f(a):
    return a

b = "x"
c = b
d = f(c)

e = [f(b), f(c), f(d)]

何をname(e[2])返す必要があり、その理由は何ですか?

于 2009-10-08T16:54:37.693 に答える
2

逆のdictを使用します。

fun_dict = {'fun1': fun1,
            'fun2': fun2,
            'fun3': fun3}

r_dict = dict(zip(fun_dict.values(), fun_dict.keys()))

reverse dictは、各関数参照を、fun_dictで指定した正確な名前にマップします。これは、関数を定義したときに使用した名前である場合とそうでない場合があります。そして、この手法は整数を含む他のオブジェクトに一般化されます。

さらなる楽しさと狂気のために、あなたは同じ辞書に順方向と逆方向の値を保存することができます。文字列を文字列にマッピングする場合はそうしませんが、関数参照や文字列などを実行する場合は、それほどクレイジーではありません。

于 2009-10-08T18:03:44.090 に答える
1

def前述のように、オブジェクトは一般に、どの変数がオブジェクトにバインドされているかを認識せず、認識できませんが、 doで定義された関数は、__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
于 2009-10-08T16:03:22.117 に答える
1

また、関数の名前を付けたいのは、関数の名前を2回記述せずに作成したいからです。これはfun_dict、バグを作成するための良い方法のように思われるためです。

この目的のためにgetattr、既知の名前でオブジェクトを取得できるすばらしい関数があります。したがって、たとえば次のようにすることができます。

funcs.py:

def func1(): pass
def func2(): pass

main.py:

import funcs
option = command_line_option()
getattr(funcs, option)()
于 2009-10-08T17:02:37.757 に答える
1

私はこれが遅い答えであることを知っています。

  1. 関数名を取得するには、次を使用できますfunc.__name__
  2. nameまたは__name__メソッドを持たないPythonオブジェクトの名前を取得します。モジュールメンバーを反復処理できます。

元:。

# package.module1.py

obj = MyClass()



# package.module2.py
import importlib
def get_obj_name(obj):
   mod = Obj.__module__ # This is necessary to 
   module = module = importlib.import_module(mod)
   for name, o in module.__dict__.items():
      if o == obj:
         return name

パフォーマンスに関する注意:大きなモジュールでは使用しないでください。

于 2021-08-11T14:11:21.897 に答える
0

変数名は、globals()およびlocals()dictsにあります。しかし、彼らはあなたが上で探しているものをあなたに与えません。「bla」には、変数ではなく、my_listの各項目の値が含まれます。

于 2009-10-08T15:12:23.017 に答える
0

一般に、このようなことをしたい場合は、これらすべての関数を保持するクラスを作成し、明確なプレフィックス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()
于 2009-10-08T16:53:33.670 に答える
0

同じ質問をしているときにこのページに出くわしました。

__name__他の人が指摘しているように、関数の名前を決定するために関数から属性を取得するだけで十分簡単です。それは、決定するための正しい方法を持たないオブジェクト__name__、つまり、ベースストリングインスタンス、int、longなどのベース/プリミティブオブジェクトではわずかにトリッキーです。

簡単に言えば、おそらくinspectモジュールを使用して、それがどれであるかについて知識に基づいた推測を行うことができますが、適切なフレームを見つけるには、スタックで作業している/スタックをトラバースしているフレームを知る必要があります。しかし、これがeval/execされたコードを処理しようとするとどれほど楽しいか想像したくありません。

% 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()
于 2014-04-24T02:29:50.377 に答える
0

を定義しclass、Unicodeプライベート関数を追加しますclass

class example:
  def __init__(self, name):
    self.name = name

  def __unicode__(self):
    return self.name

もちろんself.name、オブジェクトの名前である変数を追加する必要があります。

于 2015-05-03T21:48:39.683 に答える
0

これが私の答えです、私も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ループで使用されている単語を除外したいので、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'
    >>>

これがお役に立てば幸いです。

于 2016-08-31T03:42:47.300 に答える
0

Pythonには、名前空間と呼ばれるハッシュマップ内のオブジェクトにマップされる名前があります。いつでも、名前は常に1つのオブジェクトを参照しますが、1つのオブジェクトは任意の数の名前で参照できます。名前を指定すると、ハッシュマップがその名前が参照する単一のオブジェクトを検索するのは非常に効率的です。ただし、前述のように複数の名前で参照できるオブジェクトが与えられた場合、それを参照する名前を検索する効率的な方法はありません。名前空間内のすべての名前を繰り返し処理し、それぞれを個別にチェックして、指定されたオブジェクトにマップされるかどうかを確認する必要があります。これは、リスト内包表記を使用して簡単に行うことができます。

[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明らかに、非常に大きな名前空間では、全体をトラバースする必要があるため、この検索は遅くなる可能性があります。

于 2019-01-24T14:46:11.213 に答える
0

あなたがやろうとしているように見えることに基づいて、あなたはこのアプローチを使うことができます。

あなたの場合、あなたの関数はすべてモジュールfooにあります。次に、次のことができます。

import foo

func_name = parse_commandline()
method_to_call = getattr(foo, func_name)
result = method_to_call()

またはもっと簡潔に:

import foo

result = getattr(foo, parse_commandline())()
于 2020-09-24T19:42:34.210 に答える