Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
622 views
in Technique[技术] by (71.8m points)

runtime - Python dynamic class methods

Say there is:

class A(B):
    ...

where B could be object and ... is not:

@classmethod # or @staticmethod
def c(cls): print 'Hello from c!'

What do I have to do that calling A.c() wont trigger AttributeError?

In other words, I know it is possible to manually add class methods to a class at runtime. But is it possible to do so automatically, say every time a class method is missing it creates some dummy method?

In yet another words, only if I could replace A.__dict__ with my dict which handles __getitem__ - but A.__dict__ seems to be not writable...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can achieve this by using a __getattr__ hook on a metaclass.

class DefaultClassMethods(type):
    def __getattr__(cls, attr):
        def _defaultClassMethod(cls):
            print 'Hi, I am the default class method!'
        setattr(cls, attr, classmethod(_defaultClassMethod))
        return getattr(cls, attr)

Demo:

>>> class DefaultClassMethods(type):
...     def __getattr__(cls, attr):
...         def _defaultClassMethod(cls):
...             print 'Hi, I am the default class method!'
...         setattr(cls, attr, classmethod(_defaultClassMethod))
...         return getattr(cls, attr)
... 
>>> class A(object):
...     __metaclass__ = DefaultClassMethods
... 
>>> A.spam
<bound method DefaultClassMethods._defaultClassMethod of <class '__main__.A'>>
>>> A.spam()
Hi, I am the default class method!

Note that we set the result of the classmethod call straight onto the class, effectively caching it for future lookups.

If you need to regenerate the class method on every call instead, use the same method to bind a function to an instance but with the class and metaclass instead (using cls.__metaclass__ to be consistent with metaclass subclassing):

from types import MethodType

class DefaultClassMethods(type):
    def __getattr__(cls, attr):
        def _defaultClassMethod(cls):
            print 'Hi, I am the default class method!'
        return _defaultClassMethod.__get__(cls, cls.__metaclass__)

For static methods just return the function directly in all cases, no need to muck with the staticmethod decorator or the descriptor protocol.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...