Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>An elegant way to do it is described in Michael Foord's Voidspace blog in an entry about what metaclasses are and how to use them in the section titled <a href="http://www.voidspace.org.uk/python/articles/metaclasses.shtml#a-method-decorating-metaclass" rel="nofollow noreferrer">A Method Decorating Metaclass</a>. Simplifying it slightly and applying it to your situation resulted in this:</p> <pre><code>from types import FunctionType from functools import wraps def wrapper(method): @wraps(method) def wrapped(*args, **kwrds): # ... &lt;do something to/with "method" or the result of calling it&gt; return wrapped class MetaClass(type): def __new__(meta, classname, bases, classDict): newClassDict = {} for attributeName, attribute in classDict.items(): if isinstance(attribute, FunctionType): # replace it with a wrapped version attribute = wrapper(attribute) newClassDict[attributeName] = attribute return type.__new__(meta, classname, bases, newClassDict) class MyClass(object): __metaclass__ = MetaClass # wrap all the methods def method1(self, ...): # ...etc ... </code></pre> <p>In Python, function/method decorators are just function wrappers plus some syntactic sugar to make using them easy (and prettier).</p> <p><strong>Python 3 Compatibility Update</strong></p> <p>The previous code uses Python 2.x metaclass syntax which would need to be translated in order to be used in Python 3.x, however it would then no longer work in the previous version. This means it would need to use:</p> <pre><code>class MyBase(metaclass=MetaClass) ... </code></pre> <p>instead of:</p> <pre><code>class MyBase(object): __metaclass__ = MetaClass" ... </code></pre> <p>If desired, it's possible to write code which is compatible both both Python 2.x <em>and</em> 3.x, but doing so requires using a slightly more complicated technique which dynamically creates a new base class that inherits the desired metaclass, thereby avoiding errors due to the syntax differences between the two versions of Python. This is basically what Benjamin Peterson's <a href="http://pythonhosted.org/six/" rel="nofollow noreferrer">six</a> module's <a href="http://pythonhosted.org/six/#six.with_metaclass" rel="nofollow noreferrer"><code>with_metaclass()</code></a> function does.</p> <pre><code>from types import FunctionType from functools import wraps def wrapper(method): @wraps(method) def wrapped(*args, **kwrds): print('{!r} executing'.format(method.__name__)) return method(*args, **kwrds) return wrapped class MetaClass(type): def __new__(meta, classname, bases, classDict): newClassDict = {} for attributeName, attribute in classDict.items(): if isinstance(attribute, FunctionType): # replace it with a wrapped version attribute = wrapper(attribute) newClassDict[attributeName] = attribute return type.__new__(meta, classname, bases, newClassDict) def with_metaclass(meta): """ Create an empty class with the supplied bases and metaclass. """ return type.__new__(meta, "TempBaseClass", (object,), {}) if __name__ == '__main__': # Inherit metaclass from a dynamically-created base class. class MyClass(with_metaclass(MetaClass)): @staticmethod def a_static_method(): pass @classmethod def a_class_method(cls): pass def a_method(self): pass instance = MyClass() instance.a_static_method() # Not decorated. instance.a_class_method() # Not decorated. instance.a_method() # -&gt; 'a_method' executing </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload