Reputation: 1781
I use the following workaround for "Pythonic static variables":
def static_vars(**kwargs):
"""decorator for funciotns that sets static variables"""
def decorate(func):
for k, v in kwargs.items():
setattr(func, k, v)
return func
return decorate
@static_vars(var=1)
def global_foo():
_ = global_foo
print _.var
_.var += 1
global_foo() # >>> 1
global_foo() # >>> 2
It works just as supposed to. But when I move such a decorated function inside a class I get a strange change:
class A(object):
@static_vars(var=1)
def foo(self):
bound = self.foo
unbound = A.foo
print bound.var # OK, print 1 at first call
bound.var += 1 # AttributeError: 'instancemethod' object has no attribute 'var'
def check(self):
bound = self.foo
unbound = A.foo
print 'var' in dir(bound)
print 'var' in dir(unbound)
print bound.var is unbound.var # it doesn't make much sense but anyway
a = A()
a.check() # >>> True
# >>> True
# >>> True
a.foo() # ERROR
I can not see what causes such behaviour. It seems to me that it has something to do with python descriptors protocol, all that bound vs unbound method stuff. Somehow the foo.var
attribute is accessible but is not writable.
Any help is appreciated.
P.S. I understand that static function variables are essentially class variables and this decorator is unnecessary in the second case but the question is more for understanding the Python under the hood than to get any working solution.
Upvotes: 1
Views: 100
Reputation: 1573
a.foo
doesn't return the actual function you defined; it returns a bound method of it, which wraps up the function and has self
assigned toa
.
https://docs.python.org/3/howto/descriptor.html#functions-and-methods
That guide is out of date a little, though, since unbound methods just return the function in Python 3.
So, to access the attributes on the function, you need to go through A.foo
(or a.foo.__func__
)instead of a.foo
. And this will only work in Python 3. In Python 2, I think A.foo.__func__
will work.
Upvotes: 1