0

I want to know if there is a way in python to call the name of an instance variable? For example, if I define a class

>>>class A(object):
...    def get_instance_name(self):
...        return # The name of the instance variable
>>>obj = A()
>>>obj.get_instance_name()
obj
>>>blah = A()
>>>blah.get_instance_name()
blah
3
  • 1
    No. That doesn't even make remotely sense in Python's execution model. Why do you think you need it? Commented Jul 12, 2013 at 17:26
  • For better error messages. I would much rather have an error message which lets me know which object call gives me an error in my code. Commented Jul 12, 2013 at 17:28
  • 1
    You can't call names of instance variables, you can only call functions and methods. Commented Jul 12, 2013 at 17:49

3 Answers 3

3

Raise an exception. Not only is it the appropriate way to signal an error, it's also more useful for debugging. The traceback includes the line which did the method call but also additional lines, line numbers, function names, etc. which are more useful for debugging than just a variable name. Example:

class A:
    def do(self, x):
        if x < 0:
            raise ValueError("Negative x")

def wrong(a, x):
   a.do(-x)

wrong(A(), 1)

This gives a traceback similar to this, if the exception isn't caught:

Traceback (most recent call last):
  File "...", line 1, in <module>
    wrong(A(), 1)
  File "...", line 7, in wrong
    a.do(-x)
  File "...", line 4, in do
    raise ValueError("Negative x")
ValueError: Negative x

You can also use the traceback module to get this information programmatically, even without an exception (print_stack and friends).

Sign up to request clarification or add additional context in comments.

8 Comments

Your answer is good and I upvote it, because the question was a XY problem (meta.stackexchange.com/questions/66377/what-is-the-xy-problem). But in case it should be absolutely necessary in a programm to get the name of an instance as the OP asked for, see my EDIT in which I solved the critics that you raised (only for global names; what when several names). And I don't find this code particularly hacky, the execution may be heavy if there are many many names to examine, but ii isn't hacky in my opinion
@eyquem I consider it hacky not because it's slow, but because a thing which (as I said before) doesn't really fit any useful model of Python and should never be necessary or useful.
It doesn't fit to the real Y problem of the OP, it doesn't mean that it will never fit for a peculiar need. That is for "(as I said before)" - And for the part "doesn't really fit any useful model of Python " , I find this a hazy argument: what does it mean "not fitting with a useful model" ?? - Moreover this second hazy argument is a general argument, not an argument refering to the particuliar case of the OP's Problem. So, you mix in the same sentence two levels of arguments, and then you can't pretend that you have already said.
@eyquem I was referring to my earlier comment on the question, "That doesn't even make remotely sense in Python's execution model." And I stand by that statement. Thinking in Python terms, the "name" of a value/object is as nonsensical a concept as the opinion of air in reality. And yes, my second point works on a different level: If I stop thinking in Python terms, I can understand where that concept is coming from, but I cannot imagine a use case for it (only for the much more limited "which of these objects' attributes refer to which this object", which can be seen in a different way).
OK, writing "(as I said)" was refering to your comment on the question, not on my post. I didn't see like that
|
1

globals() return a dictionary that represents the namespace of the module (the namespace is not this dictionary, this latter only represents it)

class A(object):
    def get_instance_name(self):
        for name,ob in globals().iteritems():
            if ob is self:
                return name
       
obj = A()
print obj.get_instance_name()

blah = A()
print blah.get_instance_name()

tu = (obj,blah)
print [x.get_instance_name() for x in tu]

result

obj
blah
['obj', 'blah']

.

EDIT

Taking account of the remarks, I wrote this new code:

class A(object):

    def rondo(self,nameinst,namespace,li,s,seen):
        for namea,a in namespace.iteritems():
            if a is self:
                li.append(nameinst+s+namea)
                
            if namea=='__builtins__':
                #this condition prevents the execution to go
                # in the following section elif, so that self
                # isn't searched among the cascading attributes
                # of the builtin objects and the attributes.
                # This is to avoid to explore all the big tree
                # of builtin objects and their cascading attributes.
                # It supposes that every builtin object has not
                # received the instance, of which the names are
                # searched, as a new attribute. This makes sense.
                for bn,b in __builtins__.__dict__.iteritems():
                    if b is self:
                        li.append(nameinst+'-'+b)
            elif hasattr(a,'__dict__') \
                 and not any(n+s+namea in seen for n in seen)\
                 and not any(n+s+namea in li for n in li):
                seen.append(nameinst+s+namea)
                self.rondo(nameinst+s+namea,a.__dict__,li,'.')
            else:
                seen.append(nameinst+s+namea)
            
    def get_instance_name(self):
        li = []
        seen = []
        self.rondo('',globals(),li,'')
        return li if li else None

With the following

bumbum = A()
blah = A()

print "bumbum's names:\n",bumbum.get_instance_name()

print "\nmap(lambda y:y.get_instance_name(), (bumbum,blah) :\n",map(lambda y:y.get_instance_name(), (bumbum,blah))

print "\n[y.get_instance_name() for y in (bumbum,blah)] :\n",[y.get_instance_name() for y in (bumbum,blah)]

the result is

bumbum's names:
['bumbum']

map(lambda y:y.get_instance_name(), (bumbum,blah) :
[['bumbum'], ['blah']]

[y.get_instance_name() for y in (bumbum,blah)] :
[['bumbum', 'y'], ['blah', 'y']]

The second list comprehension shows that the function get_instance_name() must be used with care. In the list comp, identifier y is assigned in turn to every element of (bumbum,blah) then the finction finds it out as a name of the instance !

.

Now, a more complex situation:

ahah = A() # ahah : first name for this instance

class B(object):
    pass

bobo = B()
bobo.x = ahah # bobo.x : second name for ahah
jupiter = bobo.x # jupiter : third name for ahah

class C(object):
    def __init__(self):
        self.azerty = jupiter # fourth name for ahah
    
ccc = C()  
kkk = ccc.azerty # kkk : fifth name for ahah

bobo.x.inxnum = 1005
bobo.x.inxwhat = kkk # bobo.x.inxwhat : fifth name for ahah
# Since bobo.x is instance ahah, this instruction also
# creates attribute inxwhat in ahah instance's __dict__ .
# Consequently, instance ahah having already 5 names, 
# this instruction adds 5 additional names, each one
#  ending with .inxwhat
# By the way, this kkk being ahah itself, it results that ahah
# is the value of its own attribute inxwhat.

print ahah.get_instance_name()

result

['bobo.x', 'bobo.x.inxwhat', 
 'ahah', 'ahah.inxwhat', 
 'jupiter', 'jupiter.inxwhat', 
 'kkk', 'kkk.inxwhat', 
 'ccc.azerty', 'ccc.azerty.inxwhat']

I concur to judge this solution a little heavy and that if a coder thinks he needs such a heavy function, it is probably because the algorithm isn't optimal. But I find interesting to see that it's possible to do this in Python though it doesn't seem evident.

I say heavy, not hacky, I don't find it's hacky, by the way.

9 Comments

That only works if it's a global variable (though it can be extended for locals, this is hacky and the whole approach fails if it isn't a variable but e.g. an object attribute), and then it only finds a variable which refers to this object, not necessarily the one that was actually used in the call.
Since you asked for flaws with the updated implementations: It completely ignores local names and other modules, so it's only complete for single-file applications without functions. It also misses references not in a __dict__. That includes virtually all collections (both built-in ones and user-defined ones which are backed by a built-in collection), properties (and other descriptors), __slots__, and probably more which slip my mind right now.
Which coding style issues, please ? - Concerning local names & other modules, I thought as you wrote: "(though it can be extended for locals" but I was too lazy to try to examine how it could be taken in account. By the way, you speak of local names inside functions outside the class A ? I wonder if it's possible to obtain the list of such local names from the outside of a function; inside, locals() furnishes them, but from outside ??? - And for the modules, I wonder how it can happen that a name of an imported module could refer to 1 instance of the class A belonging to the main module.
For locals, you could inspect the stack (sys._getframe) though this is technically an implementation default. As for modules: Consider a = A() in module mod_a and from mod_a import a as b in module mod_b (mod_a = __main__ if you insist on "belonging to the main module"). Coding stlye issues: I'm redacting that, it's not really relevant here, I just wouldn't have written the code that way myself.
Also, I just realized that this will not find anything for things like return_an_A().get_instance_name() (simplest case: A().get_instance_name()), though this is arguably an ambiguity in the spec (it would be useful for OP's use case though - not that it's a good use case).
|
0

No, you can't. Objects can have any number of names, so the question doesn't even make sense. Consider:

a1 = a2 = a3 = A()

What is the name of the instance of A()?

1 Comment

Yes we can, see my edit please. If a coder thinks an instance has only one name while it has several ones, there's a flaw in his algorithm, that doesn't meen that Python's hasn't capacity to grab all the names with a convenient code. The option taken in my EDIT is to return a list of names; then according to what is aimed at, the code must pick one name or another in this returned list.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.