【问题标题】:How can I get the name of an object?如何获取对象的名称?
【发布时间】:2010-12-05 00:45:52
【问题描述】:

有没有办法在 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

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

【问题讨论】:

  • 在这种情况下该函数应该返回什么?
  • 像往常一样,我会请您告诉我们您要解决的问题是什么。
  • @Lennart,这样更好吗?
  • 是的。因为函数确实有__name__属性。

标签: python introspection


【解决方案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

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

【讨论】:

    【解决方案2】:

    对象在 Python 中不一定有名称,因此无法获取名称。

    对象具有__name__ 属性在它们确实有名称的情况下并不罕见,但这不是标准 Python 的一部分,而且大多数内置类型都没有。

    当您创建变量时,例如上面的x, y, z,这些名称只是充当对象的“指针”或“引用”。对象本身不知道您为它使用的名称,并且您无法轻松(如果有的话)获得对该对象的所有引用的名称。

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

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

    【讨论】:

    • @smci:假设对象在 globals() 中,但它通常不是,它会对整数和许多字符串给出误报,当然忽略了许多对象没有的事实无论如何都没有名字。另外,您应该使用is
    • @smci:不,这是不正确的。他们也可能有几个名字。
    • Lennart,在foo = [MyClass()] 的情况下,我们声明了一个对象并选择不存储它。如果我们愿意,我们可以捕捉到它。因此,将 OP 的问题细化为 无法捕获其引用的用户声明的对象。仍在等待您的具有多个名称的非别名非深拷贝对象的具体示例。别再骂人了,顺便说一句。您违反了 TOS。
    • 聊天中继续讨论。我这边没有辱骂,你需要做的就是倾听和提问,你会学到的。
    • 迂腐的 prig,是的。虐待?我想说的可能应该更好。
    【解决方案3】:

    根据您尝试执行的操作,您可以使用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())()
    

    【讨论】:

      【解决方案4】:

      只要它们在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
      

      【讨论】:

      • 请注意,您可能想要not objname.startwith('_')。我得到了很多明显错误的结果,例如 id_26 或 __loader__。当然,如果您要声明以下划线开头的名称,那么您可能想要过滤掉 __ 。我发布了一个包含这些内容的答案。
      • @Six: 是的,我们可以添加一个参数 exclude 默认为 `^_' 并应用它
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        这是我的答案,我也在使用 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'
            >>>
        

        希望这能有所帮助。

        【讨论】:

          【解决方案7】:

          您定义一个class 并添加Unicode 私有函数插入class 之类的

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

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

          【讨论】:

            【解决方案8】:

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

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

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

            返回函数名

            确定函数的名称非常简单,因为它具有包含函数声明名称的 __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

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

            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
            

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                【解决方案10】:

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

                正如其他人所指出的,只需从函数中获取 __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()
                

                【讨论】:

                  【解决方案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
                  

                   

                  【讨论】:

                  • +1:当您评估 [a,b,c] 时,您有一个对象列表,变量本身与创建的结果列表无关。
                  • 如果变量是对象而不是普通变量,这是否也是如此?
                  • @Nathan:Python 中的一切都是对象。
                  【解决方案12】:

                  使用反向字典。

                  fun_dict = {'fun1': fun1,
                              'fun2': fun2,
                              'fun3': fun3}
                  
                  r_dict = dict(zip(fun_dict.values(), fun_dict.keys()))
                  

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

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

                  【讨论】:

                  • Ack,我刚刚重新阅读了您的问题,现在我明白了。首先,您想获取构建 fun_dict 的函数的名称,而这种技术对此毫无用处。我将把它留在这里,因为稍后您可能会使用反向字典,也许是在编写错误消息或其他东西时。
                  【解决方案13】:

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

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

                  funcs.py:

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

                  main.py:

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

                  【讨论】:

                  • 使用这个我最终可以调用 any 函数,对吧?这不是有点不安全吗?
                  • 你只能调用funcs命名空间内的函数。当然,您应该过滤所有用户输入,即使在 Python 中它的规则也是正确的,但是您可以使 funcs 成为一个干净的接口模块,无论如何您都应该这样做。 getattr 还允许使用默认的后备值。
                  【解决方案14】:

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

                  def f(a):
                      return a
                  
                  b = "x"
                  c = b
                  d = f(c)
                  
                  e = [f(b), f(c), f(d)]
                  

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

                  【讨论】:

                    【解决方案15】:

                    一般当你想做这样的事情时,你创建一个类来保存所有这些函数,并用一些明确的前缀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()
                    

                    【讨论】:

                      【解决方案16】:

                      请注意,尽管如前所述,对象通常不知道也不知道绑定了哪些变量,但使用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
                      

                      【讨论】:

                        【解决方案17】:

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

                        【讨论】:

                          猜你喜欢
                          • 2016-09-03
                          • 1970-01-01
                          • 1970-01-01
                          • 2011-01-28
                          • 2012-02-16
                          • 2022-08-23
                          • 1970-01-01
                          相关资源
                          最近更新 更多