2

I'm trying to access attributes of member functions, but I cannot understand why I can access only through the __dict__.

class A(object):
    def fA(self):
        print A.fA.x 
    fA.x = 2

A.fA.__dict__['x'] = 3 
#A.fa.x #AttributeError: 'instancemethod' object has no attribute 'x'
A.fA.x = 4 

Why I do get an AttributeError if I try to access 'directly'?

Cœur
  • 37,241
  • 25
  • 195
  • 267
jimifiki
  • 5,377
  • 2
  • 34
  • 60
  • 1
    You are trying to add attributes on the method in the class definition? – jdi Jul 29 '12 at 22:00
  • 1
    Why exactly do you want this? – Wooble Jul 29 '12 at 22:01
  • 1
    I want this because it's a python feature. At the beginning I did something similar when I want derived classes to set the attribute of one of their methods. I need the right pointers to the answer. – jimifiki Jul 29 '12 at 22:04
  • Yes, I'm trying to add attributes. But what I care more is to understand how the language works. I know it can easily became bad practice. – jimifiki Jul 29 '12 at 22:05
  • 1
    Reason: http://stackoverflow.com/questions/7891277/why-does-setattr-fail-on-a-bound-method – jdi Jul 29 '12 at 22:10

2 Answers2

3

Because of how instancemethod objects are implemented. They use a non-standard attribute-getter which doesn't allow access to non-standard attributes.

Amber
  • 507,862
  • 82
  • 626
  • 550
  • 1
    That's the kind of answer I wanted. Can you tell me where I can read more? I also would like to know what non-standard attributes are. Nobody told me of this notion!! – jimifiki Jul 29 '12 at 22:07
  • Read here http://stackoverflow.com/questions/7891277/why-does-setattr-fail-on-a-bound-method – jdi Jul 29 '12 at 22:10
  • That link suggests its not a certain amount of attributes. But rather the inability to do it on bound or unbound methods. – jdi Jul 29 '12 at 22:11
  • 2
    `instancemethod` is a class that's implemented in C as part of the CPython implementation. As such, it doesn't have the built-in flexibility that normal Python objects have. It does have a `__dict__` (because the C implementation provides it), but its `__getattribute__` doesn't automatically map to things in that dict. – Amber Jul 29 '12 at 22:13
2

Not sure why you'd ever do this, but...

A.fA is actually a completely separate object vs the function fA. Watch:

>>> class A(object):
...   def fA(self): pass
...   print fA
... 
<function fA at 0x10f1c2a28>
>>> A.fA
<unbound method A.fA>

As you can see, A.fA is an "unbound method", not a function. "Unbound" means that it's not associated with any instance; whereas, bound methods are tied to a specific instance. Observe:

>>> A().fA
<bound method A.fA of <__main__.A object at 0x10f1d3d10>>

Either way, methods wrap the functions that implement them:

>>> A.fA.im_func
<function fA at 0x10f1c2a28>

Notice that the address is the same as the one printed earlier.

Strangely, I cannot repro the behavior you see:

>>> A.fA.__dict__['x'] = 1
>>> A.fA.x
1

Perhaps, this difference is due to different versions of python. Here's mine:

$ python
Python 2.7.2 (default, Jun 20 2012, 16:23:33) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 

PS: A.fA.x seems to work for me just as well as A.fA.im_func.x, which surprises me... Again, I'm a little suspicious about why you are thinking about doing this. Typically, the only time you'd use __dict__ is if you were implementing __getattr__ (not to be confused with __getattribute__).

It's also rare that giving objects (esp those of fundamental types) ad-hoc attributes is a good idea. An alternative that's usually viable is to use your own map e.g.

>>> def foo(): pass
... 
>>> my_x_values = {foo: 'X'}
>>> my_x_values[foo]
'X'

Not everyone agrees about this though. Check out this other SO question: Python function attributes - uses and abuses

Community
  • 1
  • 1
allyourcode
  • 21,871
  • 18
  • 78
  • 106