Dekoruj klasę w Pythonie, definiując dekorator jako klasę

Jaki jest prosty przykład dekorowania klasy przez zdefiniowanie dekoratora jako klasy?

Próbuję osiągnąć to, co zostało zaimplementowane w Pythonie 2.6, używając PEP 3129 z wyjątkiem używania klas, a nie funkcji, jak wyjaśnia Bruce Eckel tutaj .

Następujące dzieła:

class Decorator(object):
    def __init__(self, arg):
        self.arg = arg

    def __call__(self, cls):
        def wrappedClass(*args):
            return cls(*args)
        return type("TestClass", (cls,), dict(newMethod=self.newMethod, classattr=self.arg))

    def newMethod(self, value):
        return value * 2

@Decorator("decorated class")
class TestClass(object):
    def __init__(self):
        self.name = "TestClass"
        print "init %s"%self.name

    def TestMethodInTestClass(self):
        print "test method in test class"

    def newMethod(self, value):
        return value * 3

Z tym, że wrappedclass nie jest klasą, ale funkcją, która zwraca typ klasy. Chciałbym napisać to samo wywołanie w następujący sposób:

def __call__(self, cls):
        class wrappedClass(cls):
            def __init__(self):
                ... some code here ...
        return wrappedClass

Jak to się skończy?

Nie jestem do końca pewien, co wchodzi w ""... jakiś kod ..."""

Author: Peter Mortensen, 2012-03-28

2 answers

Jeśli chcesz nadpisać new_method(), po prostu zrób to:

class Decorator(object):
    def __init__(self, arg):
        self.arg = arg
    def __call__(self, cls):
        class Wrapped(cls):
            classattr = self.arg
            def new_method(self, value):
                return value * 2
        return Wrapped

@Decorator("decorated class")
class TestClass(object):
    def new_method(self, value):
        return value * 3

Jeśli nie chcesz zmieniać __init__(), nie musisz go nadpisywać.

 14
Author: Sven Marnach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-28 14:56:21

Następnie Klasa NormalClass staje się instancją ClassWrapper :

def decorator(decor_arg):

    class ClassWrapper:
        def __init__(self, cls):
            self.other_class = cls

        def __call__(self,*cls_ars):
            other = self.other_class(*cls_ars)
            other.field += decor_arg 
            return other

    return ClassWrapper

@decorator(" is now decorated.")
class NormalClass:
    def __init__(self, name):
        self.field = name

    def __repr__(self):
        return str(self.field)

Test:

if __name__ == "__main__":

    A = NormalClass('A');
    B = NormalClass('B');

    print A
    print B
    print NormalClass.__class__

Wyjście:

A is now decorated. <br>
B is now decorated. <br>
\__main__.classWrapper
 3
Author: Cristian Garcia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 19:30:09