How can I get the name of an object in Python?
在python中有没有任何方法可以获取对象的名称?例如:
1 2 3 4 5 | 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 |
编辑:某些上下文:
实际上,我正在创建一个可以通过命令行指定的函数列表。
我有:
1 2 3 4 5 6 7 8 9 10 | def fun1: pass def fun2 pass def fun3: pass fun_dict = {'fun1': fun1, 'fun2': fun2, 'fun3': fun3} |
我从命令行中得到函数的名称,我想调用相关的函数:
1 2 3 | func_name = parse_commandline() fun_dict[func_name]() |
我之所以想要函数名是因为我想创建
1 2 3 4 | 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 |
这样我只需要写一次函数名。
对象在python中不一定有名称,因此无法获取名称。在这些情况下,对象具有
当您创建一个变量(如上面的x、y、z)时,这些名称就充当对象的"指针"或"引用"。对象本身不知道您为它使用的是什么名称,并且您不容易(如果有的话)获得对该对象的所有引用的名称。
更新:但是,函数确实有一个
1 | dict([(t.__name__, t) for t in fun_list]) |
这是不可能的,因为可能有多个变量具有相同的值,或者一个值可能没有变量,或者一个值可能只有偶然才具有与变量相同的值。
如果你真的想这样做,你可以用
1 2 3 4 5 | def variable_for_value(value): for n,v in globals().items(): if v == value: return n return None |
但是,最好首先对名称进行迭代:
1 2 3 4 5 6 | 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 |
nbsp;
如果您想获得在解释器中定义的函数或lambda或其他类似函数的对象的名称,可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | >>> 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 2 3 | def name_of_global_obj(xx): return [objname for objname, oid in globals().items() if id(oid)==id(xx)][0] |
或者,等价地:
1 2 3 4 | def name_of_global_obj(xx): for objname, oid in globals().items(): if oid is xx: return objname |
正如其他人提到的,这是一个非常棘手的问题。解决这一问题的办法不是"一刀切",甚至不是远程解决。困难(或放松)真的取决于你的处境。
我曾多次遇到过这个问题,但最近是在创建调试函数时遇到的。我希望函数将一些未知对象作为参数,并打印它们声明的名称和内容。当然,获取内容很容易,但是声明的名称是另一回事。
下面是我的一些想法。
返回函数名确定函数名非常简单,因为它具有包含函数声明名称的名称属性。
1 2 3 4 5 6 7 | name_of_function = lambda x : x.__name__ def name_of_function(arg): try: return arg.__name__ except AttributeError: pass` |
例如,如果创建函数
检查对象是否具有名称属性,如果有,则返回该属性(仅声明函数)。请注意,您可以删除此测试,因为名称仍在
将arg的值与
结果将由第一个匹配对象的名称组成,否则将为无。
1 2 3 4 5 6 7 8 9 10 | 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() 中项目的值,并将名称存储在列表中。请注意,我正在筛选以"u"开头的名称。
结果将由一个列表(对于多个匹配项)和一个字符串(对于单个匹配项)组成,否则为无。当然,您应该根据需要调整这种行为。
1 2 3 | 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 |
这是另一种思考方法。假设有一个
1 2 3 4 5 6 7 8 | def f(a): return a b ="x" c = b d = f(c) e = [f(b), f(c), f(d)] |
使用反向口述。
1 2 3 4 5 | fun_dict = {'fun1': fun1, 'fun2': fun2, 'fun3': fun3} r_dict = dict(zip(fun_dict.values(), fun_dict.keys())) |
反向dict将把每个函数引用映射到您在fun-dict中给出的确切名称,这可能是您在定义函数时使用的名称,也可能不是。而且,这种技术推广到其他对象,包括整数。
对于额外的乐趣和疯狂,您可以在同一个dict中存储正向和反向值。如果您正在将字符串映射到字符串,我不会这样做,但是如果您正在执行函数引用和字符串之类的操作,这并不太疯狂。
And the reason I want to have the name of the function is because I want to create
fun_dict without writing the names of the functions twice, since that seems like a good way to create bugs.
为此,您有一个极好的
1 2 | def func1(): pass def func2(): pass |
1 2 3 | import funcs option = command_line_option() getattr(funcs, option)() |
注意,尽管如前所述,对象一般不知道也不知道哪些变量与它们绑定,但是使用
1 2 3 4 5 6 7 8 9 10 | def fun1: pass def fun2: pass def fun3: pass fun_dict = {} for f in [fun1, fun2, fun3]: fun_dict[f.__name__] = f |
python的名称映射到称为名称空间的hashmap中的对象。在任何时刻,一个名称总是引用一个对象,但是一个对象可以被任意数量的名称引用。给定一个名称,哈希映射查找该名称所引用的单个对象是非常有效的。但是,如果给定一个对象(如前所述,该对象可以由多个名称引用),则无法有效地查找引用该对象的名称。您需要做的是遍历名称空间中的所有名称,并分别检查每个名称,看看它是否映射到给定的对象。这很容易通过列表理解来实现:
1 | [k for k,v in locals().items() if v is myobj] |
这将计算为包含当前映射到对象
1 2 3 4 5 6 7 8 | >>> 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'] |
当然,
这是我的答案,我也在使用globals().items()。
1 2 3 4 5 | def get_name_of_obj(obj, except_word =""): for name, item in globals().items(): if item == obj and name != except_word: return name |
我添加了except-word,因为我想过滤掉for循环中使用的一些单词。如果不添加它,for循环中的关键字可能会混淆此函数,有时像下面的"each_item"这样的关键字可能会显示在函数的结果中,这取决于您对循环所做的操作。
如。
1 2 | for each_item in [objA, objB, objC]: get_name_of_obj(obj,"each_item") |
如。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | >>> 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' >>> |
希望这能有所帮助。
定义一个
1 2 3 4 5 6 | class example: def __init__(self, name): self.name = name def __unicode__(self): return self.name |
当然,您必须添加额外的变量
我在想同一个问题的时候偶然看到了这一页。
正如其他人所指出的,从函数中获取
长话短说,您可能可以使用inspect模块对它是哪个进行有根据的猜测,但您可能必须知道您在哪个帧中工作/向下遍历堆栈才能找到正确的帧。但我不想想象这会给处理eval/exec'ed代码带来多大的乐趣。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | % 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'] [] % |
我的名字是什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #!/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() |
通常,当您想要这样做时,您创建一个类来保存所有这些函数,并用一些清晰的前缀
如其他答案中所述,您可以使用
像这样:
1 2 3 4 5 6 7 8 9 10 | 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() |
变量名可以在globals()和locals()dicts中找到。但他们不会给你你想要的东西。"bla"将包含我的_列表中每个项目的值,而不是变量。