jleeothon jleeothon -4 years ago 118
Python Question

How to add a classmethod in Python dynamically

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

class HappyClass(object):
@classmethod
def say_hello():
print('hello')
HappyClass.say_hello() # hello
HappyClass().say_hello() # hello


However, I don't seem to be able to create class methods dynamically AND let them be called from instances. Let's say I want something like

class SadClass(object):
def __init__(self, *args, **kwargs):
# create a class method say_dynamic

SadClass.say_dynamic() # prints "dynamic!"
SadClass().say_dynamic() # prints "dynamic!"


I've played with
cls.__dict__
(which produces exceptions), and with
setattr(cls, 'say_dynamic', blahblah)
(which only makes the thingie callable from the class and not the instance).

If you ask me why, I wanted to make a lazy class property. But it cannot be called from instances.

@classmethod
def search_url(cls):
if hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url


Maybe because the property hasn't been called from the class yet...

In summary, I want to add a lazy, class method that can be called from the instance... Can this be achieved in an elegant (nottoomanylines) way?

Any thoughts?

How I achieved it

Sorry, my examples were very bad ones :\

Anyway, in the end I did it like this...

@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


And the
setattr
does work, but I had made a mistake when testing it...

Answer Source

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
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download