Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setattr fail on a bound method

In the following, setattr succeeds in the first invocation, but fails in the second, with:

AttributeError: 'method' object has no attribute 'i'

Why is this, and is there a way of setting an attribute on a method such that it will only exist on one instance, not for each instance of the class?

class c:

    def m(self):

        print(type(c.m))
        setattr(c.m, 'i', 0)

        print(type(self.m))
        setattr(self.m, 'i', 0)

Python 3.2.2

like image 895
tjm Avatar asked Oct 25 '11 14:10

tjm


People also ask

What is use of Setattr () method in inheritance?

What is the use of the setattr() method in inheritance? The use case of setattr() in inheritance is the same, i.e., to assign value to the attributes of an object.

What is the Setattr () used for?

Python setattr() Python setattr() function is used to assign a new value to the attribute of an object/instance. Setattr in python sets a new specified value argument to the specified attribute name of a class/function's defined object.

What is Setattr () ie setter methods used for?

Python setattr() method is used to assign the object attribute its value.

What does Setattr return?

setattr() Return Value The setattr() method returns None .


2 Answers

The short answer: There is no way of adding custom attributes to bound methods.

The long answer follows.

In Python, there are function objects and method objects. When you define a class, the def statement creates a function object that lives within the class' namespace:

>>> class c:
...     def m(self):
...         pass
...
>>> c.m
<function m at 0x025FAE88>

Function objects have a special __dict__ attribute that can hold user-defined attributes:

>>> c.m.i = 0
>>> c.m.__dict__
{'i': 0}

Method objects are different beasts. They are tiny objects just holding a reference to the corresponding function object (__func__) and one to its host object (__self__):

>>> c().m
<bound method c.m of <__main__.c object at 0x025206D0>>
>>> c().m.__self__
<__main__.c object at 0x02625070>
>>> c().m.__func__
<function m at 0x025FAE88>
>>> c().m.__func__ is c.m
True

Method objects provide a special __getattr__ that forwards attribute access to the function object:

>>> c().m.i
0

This is also true for the __dict__ property:

>>> c().m.__dict__['a'] = 42
>>> c.m.a
42
>>> c().m.__dict__ is c.m.__dict__
True

Setting attributes follows the default rules, though, and since they don't have their own __dict__, there is no way to set arbitrary attributes.

This is similar to user-defined classes defining __slots__ and no __dict__ slot, when trying to set a non-existing slot raises an AttributeError (see the docs on __slots__ for more information):

>>> class c:
...     __slots__ = ('a', 'b')
...
>>> x = c()
>>> x.a = 1
>>> x.b = 2
>>> x.c = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'c' object has no attribute 'c'
like image 74
Ferdinand Beyer Avatar answered Oct 10 '22 02:10

Ferdinand Beyer


Q: "Is there a way of setting an attribute on a method such that it will only exist on one instance, not for each instance of the class?"

A: Yes:

class c:

    def m(self):

        print(type(c.m))
        setattr(c.m, 'i', 0)

        print(type(self))
        setattr(self, 'i', 0)

The static variable on functions in the post you link to is not useful for methods. It sets an attribute on the function so that this attribute is available the next time the function is called, so you can make a counter or whatnot.

But methods have an object instance associated with them (self). Hence you have no need to set attributes on the method, as you simply can set it on the instance instead. That is in fact exactly what the instance is for.

The post you link to shows how to make a function with a static variable. I would say that in Python doing so would be misguided. Instead look at this answer: What is the Python equivalent of static variables inside a function?

That is the way to do it in Python in a way that is clear and easily understandable. You use a class and make it callable. Setting attributes on functions is possible and there are probably cases where it's a good idea, but in general it will just end up confusing people.

like image 40
Lennart Regebro Avatar answered Oct 10 '22 02:10

Lennart Regebro