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
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:
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.
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:Function objects have a special
__dict__
attribute that can hold user-defined attributes: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__
):Method objects provide a special
__getattr__
that forwards attribute access to the function object:This is also true for the
__dict__
property: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 anAttributeError
(see the docs on__slots__
for more information):