预计阅读本页时间:-
Decorators Versus Manager Functions
Regardless of such subtleties, the Tracer class decorator example ultimately still relies on __getattr__ to intercept fetches on a wrapped and embedded instance object. As we saw earlier, all we’ve really accomplished is moving the instance creation call inside a class, instead of passing the instance into a manager function. With the original nondecorator tracing example, we would simply code instance creation differently:
class Spam: # Non-decorator version
... # Any class will do
food = Wrapper(Spam()) # Special creation syntax
@Tracer
class Spam: # Decorator version
... # Requires @ syntax at class
food = Spam() # Normal creation syntax
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
Essentially, class decorators shift special syntax requirements from the instance creation call to the class statement itself. This is also true for the singleton example earlier in this section—rather than decorating a class and using normal instance creation calls, we could simply pass the class and its construction arguments into a manager function:
instances = {}
def getInstance(aClass, *args):
if aClass not in instances:
instances[aClass] = aClass(*args)
return instances[aClass]
bob = getInstance(Person, 'Bob', 40, 10) # Versus: bob = Person('Bob', 40, 10)
Alternatively, we could use Python’s introspection facilities to fetch the class from an already-created instance (assuming creating an initial instance is acceptable):
instances = {}
def getInstance(object):
aClass = object.__class__
if aClass not in instances:
instances[aClass] = object
return instances[aClass]
bob = getInstance(Person('Bob', 40, 10)) # Versus: bob = Person('Bob', 40, 10)
The same holds true for function decorators like the tracer we wrote earlier: rather than decorating a function with logic that intercepts later calls, we could simply pass the function and its arguments into a manager that dispatches the call:
def func(x, y): # Nondecorator version
... # def tracer(func, args): ... func(*args)
result = tracer(func, (1, 2)) # Special call syntax
@tracer
def func(x, y): # Decorator version
... # Rebinds name: func = tracer(func)
result = func(1, 2) # Normal call syntax
Manager function approaches like this place the burden of using special syntax on calls, instead of expecting decoration syntax at function and class definitions.