I would like to add an attribute to an instance method in one of my classes. I tried the answer given in this question, but this answer only works for functions -- as far as I can tell.
As an example, I would like to be able to do something like:
class foo(object):
...
def bar(self):
self.bar.counter += 1
return self.bar.counter
bar.counter = 1
...
but, when I call foo().bar() I get:
AttributeError: 'instancemethod' object has no attribute 'counter'
My goal in doing this is to try to impress that the 'counter' variable is local to the bar() method, and also to avoid cluttering my class namespace with yet another attribute. Is there a way to do this? Is there a more pythonic way of doing this?
You need an
__init__
method to initialise the data member:Attaching data values directly to functions is decidedly non-Pythonic.
Sorry to dig up an older post but I came across it in my searches and actually found someone with a solution.
Here's a blog post that describes the issue you're having and how to create a decorator that does what you want. Not only will you get the functionality you need but the author does a great job of explaining why Python works this way.
http://metapython.blogspot.com/2010/11/python-instance-methods-how-are-they.html
If you want the counter to be persistent across all instances you can do the following, this is still not Pythonic at all.
In Python 3 your code would work, but in Python 2 there is some wrapping that takes place when methods are looked up.
Class vs Instance
class level: storing
counter
with the function (either directly, or by using a mutable default) effectively makes it a class level attribute as there is only ever one of the function, no matter how many instances you have (they all share the same function object).instance level: to make
counter
an instance level attribute you have to create the function in__init__
, then wrap it withfunctools.partial
(so it behaves like a normal method), and then store it on the instance -- now you have one function object for every instance.Class Level
The accepted practice for a static-like variable is to use a mutable default argument:
If you want it to be prettier you can define your own mutable container:
and change your code like so:
Instance level
Summary
As you can see, readability took a serious hit when moving to instance level for
counter
. I strongly suggest you reevaluate the importance of emphasizing thatcounter
is part ofbar
, and if it is truly important maybe makingbar
its own class whose instances become part of the instances offoo
. If it's not really important, do it the normal way: