This question already has an answer here:
If I define a little python program as
class a():
def _func(self):
return "asdf"
# Not sure what to resplace __init__ with so that a.func will return asdf
def __init__(self, *args, **kwargs):
setattr(self, 'func', classmethod(self._func))
if __name__ == "__main__":
a.func
I receive the traceback error
Traceback (most recent call last):
File "setattr_static.py", line 9, in <module>
a.func
AttributeError: class a has no attribute 'func'
What I am trying to figure out is, how can I dynamically set a class method to a class without instantiating an object?
Edit:
The answer for this problem is
class a():
pass
def func(cls, some_other_argument):
return some_other_argument
setattr(a, 'func', classmethod(func))
if __name__ == "__main__":
print(a.func)
print(a.func("asdf"))
returns the following output
<bound method type.func of <class '__main__.a'>>
asdf
You need to
setattr(self, 'func', staticmethod(self._func))
You need to initialize class
variable=a()
to call__init__
There is no init in static class1. The basic idea: use an extra class to hold the methods
I found a meaningful way to do the work:
First, we define such a BaseClass:
Now that we have an original class:
Then we define the new method which we want to add on a new
Patcher
class:(Do not make the method name starts with an
_
in this case)Then call:
So, you'll find the new method
b(self)
is added to the originalMyClass
:2. Make the syntax less verbose, we use class decorator
Now if we have the
MethodPatcher
decalred, we need to do two things:ChildClass
ofModelPatcher
which contains the extra methods to addChildClass.patch(TargetClass)
So we soon found that the second step can be simplified by using a decorator:
We define a decorator:
And we can use it like:
3. Wrap together
So, we can now put the definition of
MethodPatcher
andpatch_method
into a single module:So we can use it freely:
4. Final solution: More simple declaration
Soon I found that the
MethodPatcher
class is not nessesary, while the@patch_method
decorator can do the work, so FINALLY we only need apatch_method
:And the usage becomes:
I'm using Python 2.7.5, and I wasn't able to get the above solutions working for me. This is what I ended up with:
You can dynamically add a classmethod to a class by simple assignment to the class object or by setattr on the class object. Here I'm using the python convention that classes start with capital letters to reduce confusion:
You can do it in this way
There are a couple of problems here:
__init__
is only run when you create an instance, e.g.obj = a()
. This means that when you doa.func
, thesetattr()
call hasn't happened_func
inside of__init__
you would need to useself._func
orself.__class__._func
self
will be an instance ofa
, if you set an attribute on the instance it will only be available for that instance, not for the class. So even after callingsetattr(self, 'func', self._func)
,a.func
will raise an AttributeErrorstaticmethod
the way you are will not do anything,staticmethod
will return a resulting function, it does not modify the argument. So instead you would want something likesetattr(self, 'func', staticmethod(self._func))
(but taking into account the above comments, this still won't work)So now the question is, what are you actually trying to do? If you really want to add an attribute to a class when initializing an instance, you could do something like the following:
However, this is still kind of weird. Now you can access
a.func
and call it without any problems, but theself
argument toa.func
will always be the most recently created instance ofa
. I can't really think of any sane way to turn an instance method like_func()
into a static method or class method of the class.Since you are trying to dynamically add a function to the class, perhaps something like the following is closer to what you are actually trying to do?