Category Catalog: General Catalog of "Systematic Learning Python"
As with function decorators, combinations of different callable types can be both good and bad for class decorators. Consider the following invalid alternative to the class decorator in the example of the article " Systematic Learning of Python - Decorators: Basic Knowledge - [Class Decorator: Implementation Method]" :
def Decorator:
def __init__(self, C):
self.C = C
def __call__(self, *args):
self.wrapped = self.C(*args)
return self
def __getattr__(self, attrname):
return getattr(self.wrapped, attrname)
@decorator
class C: # C = decorator(C)
pass
x = C()
y = C()
This code handles multiple decorated classes (each producing a new Decorator instance) and intercepts instance creation calls (running __call__
the method on each creation). However, unlike the previous version, this version is not able to handle multiple instances of a given class - each instance creation call overwrites the last saved instance. Previous versions did support multiple instances because each instance creation call produced a new independent wrapper object. More generally, each of the following two modes supports multiple wrapped instances:
def decorator(C):
class Wrapper:
def __init__(self, *args):
self.wrapped = C(*args)
return Wrapper
class Wrapper:
pass
def decorator(C):
def onCall(*args):
return Wrapper(C(*args))
return onCall
We will also examine this phenomenon later in a more practical scenario; in practice, however, we must be careful to correctly compose callable types to support our intentions and choose our presentation strategy wisely.
References:
[1] Mark Lutz. Python Learning Manual[M]. Machinery Industry Press, 2018.