views:

30

answers:

2

Can a descriptor auto-detect the name of an object passed to it?

class MyDecorator( object ):
    def __init__(self, wrapped):
        # Detect that wrapped's name is 'some_attr' here
        pass

class SomeClass( object ):
    some_attr = dict()
    wrapper = MyDecorator( some_attr )
+2  A: 

No, not really. You can hack something together with introspection of call frames, but it's not a nice -- or robust -- solution. (What would you do if SomeClass had two descriptors, some_attr=MyDecorator() and someother_attr=some_attr??)

It's better to be explicit:

def mydecorator(attr):
    class MyDecorator( object ):
        def __get__(self,inst,instcls):
            print(attr)
    return MyDecorator()

class SomeClass( object ):
    some_attr = mydecorator('some_attr')
    someother_attr = mydecorator('someother_attr')    

s=SomeClass()
s.some_attr
# some_attr

s.someother_attr
# someother_attr
unutbu
Sorry - my original post mistakenly asked about the name of the attribute itself, actually I want the name of something passed to it. Was editing the Q when you posted. :s
RobM
Instead of passing the object `some_attr`, why not pass the string name `'some_attr'`. It's easy to go from the string name to the object using `getattr`. It's much ickier going from the object `some_attr` to one of its potentially many string variable names.
unutbu
+1 better to be explicit
katrielalex
A: 

(Answering my own question for posterity.)

This is the best I've come up with so far:

class MyDecorator( object ):                                               
    def __init__(self, wrapped):                                           
        import inspect                                                     
        for name, obj in inspect.stack(2)[1][0].f_locals.iteritems():    
            if wrapped is obj:                                            
                print "wrapped attribute is called", name
                break                                                      
        else:                                                              
            raise RuntimeError("Failed to auto-detect attribute name")     
RobM