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

我想要函数名称的原因是因为我想创建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__(除非它们是lambdas)所以,在这种情况下你可以这样做:

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

如果您正在寻找在解释器中定义的函数或 lambda 或其他类似函数的对象的名称,您可以使用dill.source.getnamefrom dill。它几乎是在寻找__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'
于 2014-01-24T18:30:51.487 回答
5

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

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

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

返回函数名

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

name_of_function = lambda x : x.__name__

def name_of_function(arg):
    try:
        return arg.__name__
    except AttributeError:
        pass`

举个例子,如果你创建了函数def test_function(): passthen copy_function = test_function, then name_of_function(copy_function),它将返回test_function

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

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

  2. 将 arg 的值与 in 中的项的值进行比较,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

使用反向字典。

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

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

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

为了更加有趣和疯狂,您可以将正向和反向值存储在同一个字典中。如果您将字符串映射到字符串,我不会这样做,但是如果您正在做函数引用和字符串之类的事情,那并不太疯狂。

于 2009-10-08T18:03:44.090 回答
1

请注意,虽然如前所述,对象通常不知道也不知道绑定了哪些变量,但使用 定义的函数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
于 2009-10-08T16:03:22.117 回答
1

我想要函数名称的原因是因为我想创建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 ,您可以使用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

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

正如其他人所指出的,只需__name__从函数中获取属性以确定函数的名称就足够简单了。对于没有理智的方法来确定的__name__对象,即基本/原始对象,如基本字符串实例、整数、长整数等,这有点棘手。

长话短说,您可能可以使用检查模块对它是哪一个做出有根据的猜测,但您可能必须知道您正在工作的帧/遍历堆栈以找到正确的帧。但我不想想象尝试处理 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()
于 2014-04-24T02:29:50.377 回答
0

变量名可以在 globals() 和 locals() 字典中找到。但他们不会给你你在上面寻找的东西。"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

您定义 aclass并添加 Unicode 私有函数 insert 之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

我添加了 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'
    >>>

希望这能有所帮助。

于 2016-08-31T03:42:47.300 回答
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 回答
0

Python 的名称映射到称为命名空间的哈希图中的对象。在任何时刻,一个名称总是指代一个对象,但一个对象可以被任意数量的名称引用。给定一个名称,hashmap 查找该名称所指的单个对象非常有效。但是,给定一个object,如前所述,它可以被多个名称引用,没有有效的方法来查找引用它的名称。您需要做的是遍历命名空间中的所有名称并单独检查每个名称,看看它是否映射到您的给定对象。这可以通过列表理解轻松完成:

[k for k,v in locals().items() if v is myobj]

这将评估为一个字符串列表,其中包含当前映射到 object 的所有本地“变量”的名称 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 回答