如何在Python中获取变量的字符串表示形式?

7
我在Python中有一个变量x。如何从变量中找到字符串'x'。这是我的尝试:
def var(v,c):
  for key in c.keys():
    if c[key] == v:
      return key


def f():
  x = '321'
  print 'Local var %s = %s'%(var(x,locals()),x)  

x = '123'
print 'Global var %s = %s'%(var(x,locals()),x)
f()

结果如下:
Global var x = 123
Local var x = 321

以上的代码看起来有点不符合Python的风格。是否有更好/更短的方法可以达到相同的效果?


2
你真正想要什么?没有'x'就不会有调用,所以你可以使用print 'var x = %s' % x,但你没有。为什么? - tuergeist
将变量名转换为字符串 - Nick Dandoulakis
请问如何在Python中打印变量名?(已关闭) - fortran
重复 III:https://dev59.com/questions/lnNA5IYBdhLWcg3wgeKk - Michael Kuhn
4个回答

14

问题:我在Python中有一个变量x。如何从变量中找到字符串“x”。

回答:如果我正确理解了您的问题,您想从变量的值转到其名称。这在Python中实际上是不可能的。

在Python中,实际上并没有“变量”这样的东西。Python实际上拥有的是可以绑定对象的“名称”。对象无论绑定到哪个名称(如果有的话),都不会对该对象产生影响。它可能绑定到数十个不同的名称或没有名称。

考虑以下示例:

foo = 1
bar = foo
baz = foo

现在,假设您有一个整数对象,其值为1,并且您想向后工作并找到它的名称。你会打印什么?有三个不同的名称与该对象绑定,所有这些名称都是有效的。

print(bar is foo) # prints True
print(baz is foo) # prints True

在Python中,名称是访问对象的一种方式,因此没有直接处理名称的方法。您可能能够通过搜索locals()来查找值并恢复名称,但这充其量只是一个把戏。在上面的示例中,foobarbaz中哪个是“正确”的答案?它们都指向完全相同的对象。
附言:上述内容是我之前写过的答案的某种编辑版本。我认为这次措辞更好了。

是的,可以使用locals()函数实现。它返回局部作用域中所有变量的字典(包括对象、方法和函数)。 - elzapp
谢谢回复。我走了一条不同的路线。你之前的帖子改变了我的想法。 - Johan

7
我认为你想要的一般形式是使用repr()或对象的__repr__()方法。
关于__repr__()
被内置函数repr()和字符串转换(反引号)调用,计算对象的“官方”字符串表示。
请参阅此处的文档:object.repr(self)

是的,这也是我对OP问题的理解。您可以使用repr()来获取对象的Python语句表示形式,使用str()获取ASCII字符串表示形式,使用unicode()获取Unicode字符串表示形式。 - btk

3

stevenha给出了一个很好的答案。但是,如果你真的想要在命名空间字典中查找,你可以像这样获取特定作用域/命名空间中给定值的所有名称:

def foo1():
    x = 5
    y = 4
    z = x
    print names_of1(x, locals())

def names_of1(var, callers_namespace):
    return [name for (name, value) in callers_namespace.iteritems() if var is value]

foo1() # prints ['x', 'z']

如果你正在使用支持堆栈帧的Python(大多数都支持,包括CPython),则不需要将本地字典传递到names_of函数中;该函数可以从其调用者的帧本身检索该字典:

def foo2():
    xx = object()
    yy = object()
    zz = xx
    print names_of2(xx)

def names_of2(var):
    import inspect
    callers_namespace = inspect.currentframe().f_back.f_locals
    return [name for (name, value) in callers_namespace.iteritems() if var is value]

foo2() # ['xx', 'zz']

如果您正在使用可以分配名称属性的值类型,则可以为其命名,然后使用该名称:

class SomeClass(object):
    pass

obj = SomeClass()
obj.name = 'obj'


class NamedInt(int):
    __slots__ = ['name']

x = NamedInt(321)
x.name = 'x'

如果你正在使用类属性,并且希望它们知道自己的名称(描述符是显而易见的用例),那么你可以像 Django ORM 和 SQLAlchemy 声明式表定义中所做的那样,使用元类编程的酷技巧。

class AutonamingType(type):
    def __init__(cls, name, bases, attrs):
        for (attrname, attrvalue) in attrs.iteritems():
            if getattr(attrvalue, '__autoname__', False):
                attrvalue.name = attrname
        super(AutonamingType,cls).__init__(name, bases, attrs)

class NamedDescriptor(object):
    __autoname__ = True
    name = None
    def __get__(self, instance, instance_type):
        return self.name

class Foo(object):
    __metaclass__ = AutonamingType

    bar = NamedDescriptor()
    baaz = NamedDescriptor()

lilfoo = Foo()
print lilfoo.bar   # prints 'bar'
print lilfoo.baaz  # prints 'baaz'

1

在Python中,有三种方法可以获取对象的“字符串”表示: 1:str()

>>> foo={"a":"z","b":"y"}
>>> str(foo)
"{'a': 'z', 'b': 'y'}"

2:repr()

>>> foo={"a":"z","b":"y"}
>>> repr(foo)
"{'a': 'z', 'b': 'y'}"

3:字符串插值:

>>> foo={"a":"z","b":"y"}
>>> "%s" % (foo,)
"{'a': 'z', 'b': 'y'}"

在这种情况下,所有三种方法生成相同的输出,区别在于str()调用dict.__str__(),而repr()调用dict.__repr__()。 str()用于字符串插值,而repr()在打印列表或字典中的每个对象时由Python内部使用。

正如Tendayi Mawushe上面提到的,由repr产生的字符串不一定易读。

此外,.__str__()的默认实现是调用.__repr__(),因此如果类没有自己的.__str__()覆盖,则使用从.__repr__()返回的值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接