Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I dynamically create class methods for a class in python [duplicate]

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 
like image 303
user1876508 Avatar asked Jul 29 '13 16:07

user1876508


People also ask

How do you create a dynamic class in Python?

Python Code can be dynamically imported and classes can be dynamically created at run-time. Classes can be dynamically created using the type() function in Python. The type() function is used to return the type of the object. The above syntax returns the type of object.

How do you call a class dynamically in Python?

Python has an inbuilt library importlib to get the job done. :, How to access module method and class method dynamically bypassing package name as a param. An example is given below. ModuleTest: Will access the module methods dynamically based on the package name as param.


2 Answers

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:

# define a class object (your class may be more complicated than this...) class A(object):     pass  # a class method takes the class object as its first variable def func(cls):     print 'I am a class method'  # you can just add it to the class if you already know the name you want to use A.func = classmethod(func)  # or you can auto-generate the name and set it this way the_name = 'other_func'  setattr(A, the_name, classmethod(func)) 
like image 153
tdelaney Avatar answered Sep 21 '22 14:09

tdelaney


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 do a.func, the setattr() call hasn't happened
  • You cannot access the attributes of a class directly from within methods of that class, so instead of using just _func inside of __init__ you would need to use self._func or self.__class__._func
  • self will be an instance of a, if you set an attribute on the instance it will only be available for that instance, not for the class. So even after calling setattr(self, 'func', self._func), a.func will raise an AttributeError
  • Using staticmethod 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 like setattr(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:

class a():     def _func(self):         return "asdf"      def __init__(self, *args, **kwargs):         setattr(self.__class__, 'func', staticmethod(self._func))  if __name__ == '__main__':     obj = a()     a.func     a.func() 

However, this is still kind of weird. Now you can access a.func and call it without any problems, but the self argument to a.func will always be the most recently created instance of a. 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?

class a():     pass  def _func():     return "asdf"  a.func = staticmethod(_func)  # or setattr(a, 'func', staticmethod(_func))  if __name__ == '__main__':     a.func     a.func() 
like image 21
Andrew Clark Avatar answered Sep 21 '22 14:09

Andrew Clark