How to add a classmethod in Python dynamically

前端 未结 4 1296
無奈伤痛
無奈伤痛 2021-02-14 04:15

I\'m using Python 3. I know about the @classmethod decorator. Also, I know that classmethods can be called from instances.

class HappyClass(object):
    @classme         


        
相关标签:
4条回答
  • 2021-02-14 04:40

    How I achieved it:

    @classmethod
    def search_url(cls):
        if not hasattr(cls, '_search_url'):
            setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
        return cls._search_url
    
    0 讨论(0)
  • 2021-02-14 04:42

    You can add a function to a class at any point, a practice known as monkey-patching:

    class SadClass:
        pass
    
    @classmethod
    def say_dynamic(cls):
        print('hello')
    SadClass.say_dynamic = say_dynamic
    
    >>> SadClass.say_dynamic()
    hello
    >>> SadClass().say_dynamic()
    hello
    

    Note that you are using the classmethod decorator, but your function accepts no arguments, which indicates that it's designed to be a static method. Did you mean to use staticmethod instead?

    0 讨论(0)
  • 2021-02-14 04:49

    As a side note, you can just use an instance attribute to hold a function:

    >>> class Test:
    ...    pass
    ... 
    >>> t=Test()
    >>> t.monkey_patch=lambda s: print(s)
    >>> t.monkey_patch('Hello from the monkey patch')
    Hello from the monkey patch
    
    0 讨论(0)
  • 2021-02-14 05:02

    If you want to create class methods, do not create them in the __init__ function as it is then recreated for each instance creation. However, following works:

    class SadClass(object):
        pass
    
    def say_dynamic(cls):
        print("dynamic")
    
    SadClass.say_dynamic = classmethod(say_dynamic)
    # or 
    setattr(SadClass, 'say_dynamic', classmethod(say_dynamic))
    
    SadClass.say_dynamic() # prints "dynamic!"
    SadClass().say_dynamic() # prints "dynamic!"
    

    Of course, in the __init__ method the self argument is an instance, and not the class: to put the method in the class there, you can hack something like

    class SadClass(object):
        def __init__(self, *args, **kwargs):
            @classmethod
            def say_dynamic(cls):
                print("dynamic!")
    
            setattr(self.__class__, 'say_dynamic', say_dynamic)
    

    But it will again reset the method for each instance creation, possibly needlessly. And notice that your code most probably fails because you are calling the SadClass.say_dynamic() before any instances are created, and thus before the class method is injected.

    Also, notice that a classmethod gets the implicit class argument cls; if you do want your function to be called without any arguments, use the staticmethod decorator.

    0 讨论(0)
提交回复
热议问题