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

上面的食谱似乎有点不像pythonesque。是否有更好/更短的方法来实现相同的结果?

4

4 回答 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()以找到值并恢复名称,但这充其量只是一个客厅技巧。在我上面的例子中foobar、 和baz中的哪一个是“正确”的答案?它们都指的是完全相同的对象。

PS以上是我之前写的答案的经过编辑的版本。 我认为这次我在措辞方面做得更好。

于 2009-11-03T08:15:11.807 回答
7

我相信你想要的一般形式是对象repr()__repr__()方法。

关于__repr__()

由 repr() 内置函数和字符串转换(反引号)调用,以计算对象的“官方”字符串表示。

请参阅此处的文档:对象。代表(自我)

于 2009-11-03T07:58:17.397 回答
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 支持),则不需要将 locals dict 传递给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'
于 2009-11-03T16:20:21.463 回答
1

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

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

2:代表()

>>> 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() 用于字符串插值,而当您打印列表或字典时,Python 在内部对列表或字典中的每个对象使用 repr()。

正如 Tendayi Mawushe 上面提到的,由 repr 生成的字符串不一定是人类可读的。

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

于 2009-11-03T10:09:00.503 回答