如何在Python中获取对象的名称?

时间:2009-10-08 14:54:22

标签: python introspection

有没有办法在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而不编写两次函数的名称,因为这似乎是创建错误的好方法。我想做的是:

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

这样我只需要写一次函数名。

17 个答案:

答案 0 :(得分:27)

对象不一定在python中有名字,所以你不能得到这个名字。 对象在具有名称的情况下具有__name__属性并不罕见,但这不是标准python的一部分,并且大多数内置类型没有。

当您创建变量(如上面的x,y,z)时,这些名称只是充当对象的“指针”或“引用”。对象本身不知道您使用的是什么名称,并且您不能轻易地(如果有的话)获取该对象的所有引用的名称。

更新:但是,函数确实有__name__(除非它们是lambda),所以在这种情况下你可以这样做:

dict([(t.__name__, t) for t in fun_list])

答案 1 :(得分:11)

这实际上是不可能的,因为可能有多个变量具有相同的值,或者某个值可能没有变量,或者某个值可能只是偶然的变量值。

如果您真的想这样做,可以使用

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

答案 2 :(得分:6)

如果您想获取函数或lambda的名称或解释器中定义的其他类似函数的对象,可以使用dill中的dill.source.getname。它几乎寻找__name__方法,但在某些情况下,它知道如何为对象找到名称...或名称的其他魔法。我不想讨论如何为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'

答案 3 :(得分:5)

这种单行程适用于所有类型的对象,只要它们在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

答案 4 :(得分:2)

这是考虑它的另一种方式。假设有name()函数返回其参数的名称。给出以下代码:

def f(a):
    return a

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

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

name(e[2])应该返回什么,以及为什么?

答案 5 :(得分:2)

正如其他人所说,这是一个非常棘手的问题。对此的解决方案不是“一刀切”,甚至远程也不是。困难(或缓解)实际上取决于你的情况。

我已经多次遇到过这个问题,但最近在创建调试功能时。我希望函数将一些未知对象作为参数并打印它们声明的名称和内容。当然,获取内容很容易,但声明的名称是另一个故事。

以下是我提出的一些内容。

返回功能名称

确定函数的名称非常简单,因为它具有包含函数声明名称的 __ name __ 属性。

my $sum_xx = sum map { $_ * $_ } @x;

举个例子,如果您创建函数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,它将返回 test_function

返回第一个匹配的对象名称

  1. 检查对象是否具有 __ name __ 属性,如果是,则返回它(仅声明函数)。请注意,您可以删除此测试,因为该名称仍位于name_of_function(copy_function)

  2. 将arg的值与globals()中的项值进行比较,并返回第一个匹配项的名称。请注意,我正在过滤掉以“_”开头的名称。

  3. 结果将包含第一个匹配对象的名称,否则为None。

    globals()

    返回所有匹配的对象名称

    • 将arg的值与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 中的项目值和列表中的商店名称进行比较。请注意,我正在过滤掉以“_”开头的名称。

    结果将包含一个列表(用于多个匹配),一个字符串(用于单个匹配),否则为None。当然,您应该根据需要调整此行为。

    globals()

答案 6 :(得分:1)

  

我想要拥有该函数名称的原因是因为我想创建fun_dict而不编写两次函数的名称,因为这似乎是创建错误的好方法。

为此,您有一个很棒的getattr函数,它允许您通过已知名称获取对象。所以你可以这样做:

funcs.py:

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

main.py:

import funcs
option = command_line_option()
getattr(funcs, option)()

答案 7 :(得分:1)

使用反向字典。

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

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

反向dict会将每个函数引用映射到fun_dict中给出的确切名称,这可能是您定义函数时使用的名称,也可能不是。而且,这种技术可以推广到其他对象,包括整数。

为了获得额外的乐趣和精神错乱,您可以将正向和反向值存储在同一个词典中。如果你将字符串映射到字符串,我不会这样做,但如果你正在做类似函数引用和字符串的事情,那就不会太疯狂了。

答案 8 :(得分:1)

请注意,虽然如上所述,对象通常不会也无法知道哪些变量绑定到它们,但使用def定义的函数在__name__属性中具有名称(def属性中使用的名称{1}})。此外,如果函数在同一模块中定义(如示例中所示),则globals()将包含所需字典的超集。

def fun1:
  pass
def fun2:
  pass
def fun3:
  pass

fun_dict = {}
for f in [fun1, fun2, fun3]:
  fun_dict[f.__name__] = f

答案 9 :(得分:0)

通常,当您想要执行此类操作时,您可以创建一个类来保存所有这些函数,并使用一些明确的前缀cmd_等命名它们。然后从命令中获取字符串,并尝试从具有cmd_前缀的类中获取该属性。现在,您只需要向类中添加一个新的函数/方法,它就可供您的调用者使用。您可以使用doc字符串自动创建帮助文本。

如其他答案中所述,您可以使用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()

答案 10 :(得分:0)

变量名可以在globals()和locals()中找到。但他们不会给你上面你想要的东西。 “bla”将包含my_list的每个项目的值,而不是变量。

答案 11 :(得分:0)

我在讨论同样的问题时遇到了这个页面。

正如其他人所说,只需从函数中获取__name__属性就可以确定函数的名称。对于没有合理的方法来确定__name__,即基本/原始对象,如基本字符串实例,整数,长整数等,这一点稍微有点棘手。

长话短说,您可以使用检查模块对其中的哪一个做出有根据的猜测,但您可能必须知道您正在使用哪个框架/遍历堆栈以找到正确的框架。但是我不想想这会有多大的乐趣来处理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()

答案 12 :(得分:0)

您定义class并添加Unicode私有函数,插入class

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

  def __unicode__(self):
    return self.name

当然,您必须添加额外的变量self.name,这是对象的名称。

答案 13 :(得分: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

我添加了except_word,因为我想过滤掉for循环中使用的一些单词。 如果你没有添加它,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'
    >>>

希望这可以提供帮助。

答案 14 :(得分:0)

Python的名称映射到称为名称空间的哈希图中的对象。在任何时间,名称始终始终恰好指向一个对象,但是单个对象可以由任意数量的名称引用。给定一个名称,哈希表查找该名称所指的单个对象非常有效。但是,给定一个 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。显然,对于很大的名称空间,此搜索可能会很慢,因为必须完整遍历它们。

答案 15 :(得分:0)

根据您要尝试执行的操作,可以使用this方法。

在您的情况下,所有功能都将存在于模块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())()

答案 16 :(得分:0)

我知道这是迟到的答案。

  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 o

性能说明:不要在大型​​模块中使用它。