【问题标题】:How to print original variable's name in Python after it was returned from a function?从函数返回后如何在 Python 中打印原始变量的名称?
【发布时间】:2010-10-07 09:24:55
【问题描述】:

我有枚举并使用myEnum.SomeNameAmyEnum.SomeNameB 等变量。当我从函数返回这些变量之一时,我可以打印它们的名称(例如myEnum.SomeNameA)而不是它们返回的值?

【问题讨论】:

  • 对于调试打印,现在有一个方便的机制,带有 f 字符串 =,就像在 print(f"{foo=} {bar=}") 中一样,可以打印变量名称和值,我在以下位置进一步解释:stackoverflow.com/questions/32000934/…
  • 在此处查看我的原始帖子:stackoverflow.com/a/59364138/5088165
  • @PatrickT 我相信该方法不会做 OP 想要的,编辑此标题以澄清。

标签: python variables


【解决方案1】:

是的。

在您使用枚举的情况下,这很容易:

>>> from enum import Enum
>>> class Type(Enum):
...   AB, SBS, INTERLACED, SPLIT = range(4)
...
>>> Type.AB
<Type.AB: 0>
>>> print(Type.AB)
Type.AB
>>> Type.AB.name
'AB'
>>> Type.AB.value
0
>>> Type(0)
<Type.AB: 0>

一般来说,它可能是模棱两可的:

>>> def varname(v): d = globals(); return [k for k in d if d[k] == v]
...
>>> def varnameis(v): d = globals(); return [k for k in d if d[k] is v]
...
>>> foo = {'a':'aap'}
>>> bar = {'a':'aap'}
>>> varname(foo)
['foo', 'bar']
>>> varnameis(foo)
['foo']

甚至误导:

>>> foo = "A"; bar = "A"
>>> varnameis("A")
['foo', 'bar']
>>> foo = "An immutable value."; bar = "An immutable value."
>>> varnameis("An immutable value.")
[]
>>> foo = "An immutable value."; bar = "An immutable value."; varnameis("An immutable value.")
['foo', 'bar']
>>> import sys; sys.version
'3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 02:47:15) [MSC v.1900 32 bit (Intel)]'

要在任何范围内搜索,请使用:

>>> def varname(v, scope=None): d = globals() if not scope else vars(scope); return [k for k in d if d[k] == v]
...
>>> import time
>>> time.timezone
-3600
>>> varname(-3600)
[]
>>> varname(-3600, time)
['timezone']

为避免歧义,wrap your name with the data

【讨论】:

  • 如果您导入某些内容并将其定义为ANAME=1,并且您想将其打印为"The Name is: ANAME",您会怎么做?
  • 如果在全局范围内,varnameis(1) 应该可以。
  • 是的,我认为的问题是还有一些BNAME=1 所以它不是唯一的。正如您在上面演示的那样。因此,我不得不将其与可接受的 names 数组进行比较。
【解决方案2】:

我知道这是一个老问题,但有可能使用f strings

my_variable = some_object
f'{my_variable=}'.split('=', 1)[0]

这将打印 'my_variable'

【讨论】:

    【解决方案3】:

    Python 3.8 为此添加了一个新的并且可能LITTLE更好的解决方案:

    my_nice_variable_name = 'test'
    print(f'{my_nice_variable_name=}')
    
    # Output:
    # my_nice_variable_name='test'
    

    在这里您可以使用字符串输出。仍然不可取,但可能比其他方法好一点。

    【讨论】:

    • @ivanjermakov 不是吗?他可以使用我的技巧从函数中返回他的变量,包括他的值。
    • 哇!很简单很容易,谢谢!大声笑一个班轮:)var_name = f"{var=}"
    【解决方案4】:

    是的

    import inspect
            
    def printVariableName(abc):
        newvar=inspect.stack()[1][4][0]
        print(newvar.split("(")[1].split(")")[0])
    
    noob=10
    printVariableName(noob)
    

    输出:

    noob
    

    【讨论】:

      【解决方案5】:

      要补充@Jay's answer,一些概念...

      Python“变量”只是对值的引用。每个值占用一个给定的内存位置(参见id()

      >>> id(1)
      10052552
      
      >>> sys.getrefcount(1)
      569
      

      从上面,您可能会注意到值“1”出现在内存位置 10052552。在此解释器实例中,它被引用了 569 次。

      >>> MYVAR = 1
      >>> sys.getrefcount(1)
      570
      

      现在,看到因为另一个名称绑定到这个值,所以引用计数增加了一个。

      基于这些事实,判断单个变量名指向一个值是不现实的/不可能的。

      我认为解决您的问题的最佳方法是将映射和函数添加到您的枚举引用回字符串名称。

      myEnum.get_name(myEnum.SomeNameA) 
      

      如果您需要示例代码,请发表评论。

      【讨论】:

        【解决方案6】:

        三思而后行:

        由于 Python 不提供原生 Enum 类型,因此您不应要求提供一种,而应使用其他更强大的构造来构建您的程序。否则,下一步总是会是“为什么 Python 没有switch ...: 语句,我如何最好地模拟它?”

        由于枚举通常用于定义某种状态,因此更好的方法是: 创建一个定义属于一个状态的所有抽象属性、属性和方法的基类。然后,对于每个状态,派生一个实现该状态特定行为的子类。然后,您可以传递这些类(或者它们的实例)来处理状态及其行为。

        如果您使用类而不是实例(“单例”的 Python 方式),您可以通过 if current_state is StateA: 简单地检查任何给定的状态(不是必须的)(注意 is 而不是 @ 987654324@) 与比较整数值相比没有性能损失。

        当然,您可以定义name 属性和__str__() 方法来访问和打印州名。

        【讨论】:

          【解决方案7】:

          只要用你要打印的文本作为枚举的值,如

          class MyEnum (object):
              valueA = "valueA"
              valueB = "valueB"
          

          在 Python 中比较字符串的同一性几乎与比较整数值一样有效(这是因为字符串是不可变的,因为具有哈希值)

          当然,首先有更简单的方法来创建枚举:

          class Enum (object):
              def __init__(self, *values):
                  for v in values:
                      self.__dict__[v] = v
          

          然后,像这样创建您的枚举:

          MyEnum = Enum("valueA", "valueB")
          

          ans 访问方式同上:

          MyEnum.valueA
          

          【讨论】:

          • +1:枚举的好方法。一般来说,它们是无用的,但这是一个整洁的解决方案。
          • 这完全不是pythonic。使用此类而不是 dict 可能有什么优势。 (不是,但不赞成。合法的答案)
          • @muhuk:dict 模拟枚举行为有什么用?在我的示例中, Enum() 类的目的是提供对作为命名属性与文字的值的访问。我不明白为什么这是非pythonic;我同意应该完全避免使用枚举,正如您可以从该主题的其他答案中看到的那样。
          • 枚举可能应该是不可变的,因此所有属性都必须在 __new__() 中设置。
          • 但是如果想要的分配值不同怎么办,比如 int?
          【解决方案8】:

          这个问题有两个答案:YesNo

          你能做到吗? -- 是(在大多数情况下) 这值得么? -- 否(在大多数情况下)

          怎么做:

          这取决于枚举的实现。例如:

          class Enum:
              A = 1
              B = 2
          

          如果你知道枚举类对象并且它们都是名字(或至少是一个唯一的前缀),那么是否有 100 个名字是指一个你想找到的整数的名字并不重要

          对于上面的示例as @batbrat suggested,您可以使用namestr() 检查“Enum.__dict__”:

           >>> getEnum = lambda: Enum.A
           >>> namestr(getEnum(), Enum.__dict__)
           >>> ['A']
          

          在这种情况下,您甚至不必知道所有枚举名称。如果枚举以不同的方式实现,那么您可能需要使用不同的 hack。在大多数情况下会有一些解决方案,例如,请参阅@Jay's answer。不过没关系,因为..

          值得吗?

          • 一些枚举实现可能需要丑陋、复杂且最终不可靠的 hack 来实现 namestr()

          • Enum 类可以自行返回答案(参见@David's@Ber's@gahooa's 答案)。

          • 作为@Ber pointed out,Python 中没有内置的 Enum 和 switch 语句(参见PEP-0275PEP-3103)。值得研究没有枚举的解决方案。

          【讨论】:

            【解决方案9】:

            没有唯一的或原始的变量名这样的东西 http://www.amk.ca/quotations/python-quotes/page-8

            就像你得到你在门廊上发现的那只猫的名字一样:猫(物体)本身不能告诉你它的名字,它并不真正关心——所以唯一的方法就是找出它是什么调用是询问你所有的邻居(命名空间)是否是他们的猫(对象)......

            ....如果您发现它有很多名字,或者根本没有名字,请不要感到惊讶!

            Fredrik Lundh,2000 年 11 月 3 日,回答问题“当我拥有 PyObject* 时,如何从 C++ 中获取变量的名称?”

            【讨论】:

              【解决方案10】:

              简短的回答:不。

              长答案:使用回溯、检查等一些丑陋的黑客攻击是可能的,但通常不建议将其用于生产代码。例如参见:

              也许您可以使用解决方法将值转换回名称/表示字符串。如果您发布更多示例代码和有关您想要此内容的详细信息,也许我们可以提供更深入的帮助。

              【讨论】:

              • 你将如何定义一个打印出变量值和变量名的函数?比如说,一个月中的几天,通过输入一个月的名称,它应该吐回“month_name has x days”。必须有办法,除非我必须要求用户输入所选月份(在本例中)两次!
              • a = 1; b = a1 叫什么名字?
              【解决方案11】:

              据我所知,这需要一些自省。您可以尝试使用检查模块。

              在此之前您可能想尝试一些简单的事情:

              1. 这不是应该使用的确切代码。在打印之前,您必须从 __dict__ 检索变量名称。 打印 myEnum.__dict__
              2. 如果要从函数内部打印变量名称,可以尝试 函数 - vars()、locals() 和 globals()。
                编辑
                我刚刚注意到这不是你想要的。在这种情况下,添加一个 dict 和一个函数可以工作
              3. 您可能想要打印枚举类的 __dict__ 。

              话虽如此,Python 中没有标准枚举。了解您如何创建它们会有所帮助。

              再想一想,您可以将变量维护为枚举中的字典,以变量名称为键,并提供一种枚举方法来查找正确的变量并打印其名称。这种解决方案(保留 dict)很糟糕,因为变量值不一定是唯一的。

              编辑
              这个问题并非微不足道,因此您可能需要使用经过验证的解决方案。恕我直言,如果可以的话,你最好避免这种情况。

              【讨论】:

                【解决方案12】:

                Erlang 有一个叫做“原子”的概念——它们类似于字符串常量或枚举。考虑使用字符串常量作为枚举的值——与枚举的名称相同。

                【讨论】:

                  【解决方案13】:

                  您可以将规范名称存储为实例的属性,然后将其分配给具有相同名称的变量。这可能有效:

                  class MyEnum(object):
                      def __new__(cls, name):
                          try:
                              return getattr(MyEnum, name)
                          except AttributeError:
                              e = super(MyEnum, cls).__new__(cls)
                              e.name = name
                              setattr(MyEnum, name, e)
                              return e
                  

                  无论如何,这并不是一件特别“Pythonic”的事情。

                  【讨论】:

                    猜你喜欢
                    • 2023-02-09
                    • 1970-01-01
                    • 2018-05-09
                    • 2015-09-04
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-03-12
                    相关资源
                    最近更新 更多