Reputation: 1138
I'm attempting to create some decorators which will allow class members to be decorated on instantiation, because I'd like to have some instances which are decorated and others which aren't.
In the example below, the intended outcome of applying the once
decorator to an instance of SomeClass
is that when some_func
has been called, calling other_func
prints a message rather than calling the original function.
#!/usr/bin/env python
import functools
def some_once(func):
@functools.wraps(func)
def wrapped(self, *args, **kwargs):
if not self._new_attr:
print("don't have new attr yet")
func(self, *args, **kwargs)
self._new_attr = True
return wrapped
def other_once(func):
@functools.wraps(func)
def wrapped(self, *args, **kwargs):
if self._new_attr:
print("We have a new attr")
else:
func(self, *args, **kwargs)
return wrapped
def once(cls):
setattr(cls, "_new_attr", False)
setattr(cls, "some_func", some_once(cls.some_func))
setattr(cls, "other_func", other_once(cls.other_func))
return cls
class SomeClass:
def some_func(self, parameter):
return "The parameter is " + str(parameter)
def other_func(self, parameter):
return "The other parameter is " + str(parameter)
if __name__ == '__main__':
a = SomeClass()
print(dir(a))
print(a.some_func("p1"))
print(a.other_func("p2"))
b = once(SomeClass())
print(dir(b))
print(b.some_func("p3"))
print(b.other_func("p4"))
The problem that results is that rather than looking at self._new_attr
, the decorated functions instead look at string._new_attr
, where the string is the parameter to the functions. I'm confused about what I'm doing wrong here.
Upvotes: 1
Views: 211
Reputation: 85522
Don't decorate an instance. Make a new, decorated class.
Changing this line:
b = once(SomeClass())
into:
b = once(SomeClass)()
Should do the trick. once(SomeClass)
gives you a new, decorated class. In the next step make an instance of it.
Upvotes: 1