预计阅读本页时间:-
Increasing Levels of Magic
Most of this book has focused on straightforward application-coding techniques, as most programmers spend their time writing modules, functions, and classes to achieve real-world goals. They may use classes and make instances, and might even do a bit of operator overloading, but they probably won’t get too deep into the details of how their classes actually work.
However, in this book we’ve also seen a variety of tools that allow us to control Python’s behavior in generic ways, and that often have more to do with Python internals or tool building than with application-programming domains:
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
Introspection attributes
Special attributes like __class__ and __dict__ allow us to inspect internal implementation aspects of Python objects, in order to process them generically—to list all attributes of an object, display a class’s name, and so on.
Operator overloading methods
Specially named methods such as __str__ and __add__ coded in classes intercept and provide behavior for built-in operations applied to class instances, such as printing, expression operators, and so on. They are run automatically in response to built-in operations and allow classes to conform to expected interfaces.
Attribute interception methods
A special category of operator overloading methods provide a way to intercept attribute accesses on instances generically: __getattr__, __setattr__, and __getattribute__ allow wrapper classes to insert automatically run code that may validate attribute requests and delegate them to embedded objects. They allow any number of attributes of an object—either selected attributes, or all of them—to be computed when accessed.
Class properties
The property built-in allows us to associate code with a specific class attribute that is automatically run when the attribute is fetched, assigned, or deleted. Though not as generic as the prior paragraph’s tools, properties allow for automatic code invocation on access to specific attributes.
Class attribute descriptors
Really, property is a succinct way to define an attribute descriptor that runs functions on access automatically. Descriptors allow us to code in a separate class __get__, __set__, and __delete__ handler methods that are run automatically when an attribute assigned to an instance of that class is accessed. They provide a general way to insert automatically run code when a specific attribute is accessed, and they are triggered after an attribute is looked up normally.
Function and class decorators
As we saw in Chapter 38, the special @callable syntax for decorators allows us to add logic to be automatically run when a function is called or a class instance is created. This wrapper logic can trace or time calls, validate arguments, manage all instances of a class, augment instances with extra behavior such as attribute fetch validation, and more. Decorator syntax inserts name-rebinding logic to be run at the end of function and class definition statements—decorated function and class names are rebound to callable objects that intercept later calls.
As mentioned in this chapter’s introduction, metaclasses are a continuation of this story—they allow us to insert logic to be run automatically when a class object is created, at the end of a class statement. This logic doesn’t rebind the class name to a decorator callable, but rather routes creation of the class itself to specialized logic.
In other words, metaclasses are ultimately just another way to define automatically run code. Via metaclasses and the other tools just listed, Python provides ways for us to interject logic in a variety of contexts—at operator evaluation, attribute access, function calls, class instance creation, and now class object creation.
Unlike class decorators, which usually add logic to be run at instance creation time, metaclasses run at class creation time; as such, they are hooks generally used for managing or augmenting classes, instead of their instances.
For example, metaclasses can be used to add decoration to all methods of classes automatically, register all classes in use to an API, add user-interface logic to classes automatically, create or extend classes from simplified specifications in text files, and so on. Because we can control how classes are made (and by proxy the behavior their instances acquire), their applicability is potentially very wide.
As we’ve also seen, many of these advanced Python tools have intersecting roles. For example, attributes can often be managed with properties, descriptors, or attribute interception methods. As we’ll see in this chapter, class decorators and metaclasses can often be used interchangeably as well. Although class decorators are often used to manage instances, they can be used to manage classes instead; similarly, while metaclasses are designed to augment class construction, they can often insert code to manage instances, too. Since the choice of which technique to use is sometimes purely subjective, knowledge of the alternatives can help you pick the right tool for a given task.