views:

351

answers:

4

I have a variable x in python. How can i find the string 'x' from the variable. Here is my attempt:

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

The results are:

Global var x = 123
Local var x = 321

The above recipe seems a bit un-pythonesque. Is there a better/shorter way to achieve the same result?

+2  A: 

I believe the general form of what you want is repr() or the __repr__() method of an object.

with regards to __repr__():

Called by the repr() built-in function and by string conversions (reverse quotes) to compute the “official” string representation of an object.

See the docs here: object.repr(self)

Gabriel Hurley
+10  A: 

Q: I have a variable x in python. How can i find the string 'x' from the variable.

A: If I am understanding your question properly, you want to go from the value of a variable to its name. This is not really possible in Python.

In Python, there really isn't any such thing as a "variable". What Python really has are "names" which can have objects bound to them. It makes no difference to the object what names, if any, it might be bound to. It might be bound to dozens of different names, or none.

Consider this example:

foo = 1
bar = foo
baz = foo

Now, suppose you have the integer object with value 1, and you want to work backwards and find its name. What would you print? Three different names have that object bound to them, and all are equally valid.

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

In Python, a name is a way to access an object, so there is no way to work with names directly. You might be able to search through locals() to find the value and recover a name, but that is at best a parlor trick. And in my above example, which of foo, bar, and baz is the "correct" answer? They all refer to exactly the same object.

P.S. The above is a somewhat edited version of an answer I wrote before. I think I did a better job of wording things this time.

steveha
Yes, that's possible using the locals() function. It returns a dictionary of all the variables in the local scope (including objects, methods and functions).
elzapp
Thanks for the reply. I got carried away on different track. Your previous post changed my mind on what I wanted to do.
Johan
A: 

There are three ways to get "the" string representation of an object in 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: string interpolation:

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

In this case all three methods generated the same output, the difference is that str() calls dict.__str__(), while repr() calls dict.__repr__(). str() is used on string interpolation, while repr() is used by Python internally on each object in a list or dict when you print the list or dict.

As Tendayi Mawushe mentiones above, string produced by repr isn't necessarily human-readable.

elzapp
+1  A: 

stevenha has a great answer to this question. But, if you actually do want to poke around in the namespace dictionaries anyway, you can get all the names for a given value in a particular scope / namespace like this:

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']

If you're working with a Python that has stack frame support (most do, CPython does), it isn't required that you pass the locals dict into the names_of function; the function can retrieve that dictionary from its caller's frame itself:

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']

If you're working with a value type that you can assign a name attribute to, you can give it a name, and then use that:

class SomeClass(object):
    pass

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


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

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

Finally, if you're working with class attributes and you want them to know their names (descriptors are the obvious use case), you can do cool tricks with metaclass programming like they do in the Django ORM and SQLAlchemy declarative-style table definitions:

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'
Matt Anderson