具体见The Python Language Reference
与Attribute相关的有
__get__
__set__
__getattribute__
__getattr__
__setattr__
__getitem__
__setitem__
Reference描述如下
3.3.2. Customizing attribute access
The following methods can be defined to customize the meaning of attribute access (use of, assignment to, or deletion of
x.name
) for class instances.
object.
__getattr__
(self, name)Called when the default attribute access fails with an
AttributeError
(either__getattribute__()
raises anAttributeError
because name is not an instance attribute or an attribute in the class tree forself
; or__get__()
of a name property raisesAttributeError
). This method should either return the (computed) attribute value or raise anAttributeError
exception.Note that if the attribute is found through the normal mechanism,
__getattr__()
is not called. (This is an intentional asymmetry between__getattr__()
and__setattr__()
.) This is done both for efficiency reasons and because otherwise__getattr__()
would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the__getattribute__()
method below for a way to actually get total control over attribute access.
object.
__getattribute__
(self, name)Called unconditionally to implement attribute accesses for instances of the class. If the class also defines
__getattr__()
, the latter will not be called unless__getattribute__()
either calls it explicitly or raises anAttributeError
. This method should return the (computed) attribute value or raise anAttributeError
exception. In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example,object.__getattribute__(self, name)
.Note
This method may still be bypassed when looking up special methods as the result of implicit invocation via language syntax or built-in functions. See Special method lookup.
object.
__setattr__
(self, name, value)Called when an attribute assignment is attempted. This is called instead of the normal mechanism (i.e. store the value in the instance dictionary). name is the attribute name, value is the value to be assigned to it.
If
__setattr__()
wants to assign to an instance attribute, it should call the base class method with the same name, for example,object.__setattr__(self, name, value)
.
object.
__delattr__
(self, name)Like
__setattr__()
but for attribute deletion instead of assignment. This should only be implemented ifdelobj.name
is meaningful for the object.
object.
__dir__
(self)Called when
dir()
is called on the object. A sequence must be returned.dir()
converts the returned sequence to a list and sorts it.3.3.2.1. Customizing module attribute access
Special names
__getattr__
and__dir__
can be also used to customize access to module attributes. The__getattr__
function at the module level should accept one argument which is the name of an attribute and return the computed value or raise anAttributeError
. If an attribute is not found on a module object through the normal lookup, i.e.object.__getattribute__()
, then__getattr__
is searched in the module__dict__
before raising anAttributeError
. If found, it is called with the attribute name and the result is returned.The
__dir__
function should accept no arguments, and return a list of strings that represents the names accessible on module. If present, this function overrides the standarddir()
search on a module.For a more fine grained customization of the module behavior (setting attributes, properties, etc.), one can set the
__class__
attribute of a module object to a subclass oftypes.ModuleType
. For example:import sys from types import ModuleType class VerboseModule(ModuleType): def __repr__(self): return f'Verbose {self.__name__}' def __setattr__(self, attr, value): print(f'Setting {attr}...') super().__setattr__(attr, value) sys.modules[__name__].__class__ = VerboseModule
Note
Defining module
__getattr__
and setting module__class__
only affect lookups made using the attribute access syntax – directly accessing the module globals (whether by code within the module, or via a reference to the module’s globals dictionary) is unaffected.Changed in version 3.5:
__class__
module attribute is now writable.New in version 3.7:
__getattr__
and__dir__
module attributes.See also
PEP 562 - Module __getattr__ and __dir__
- Describes the
__getattr__
and__dir__
functions on modules.3.3.2.2. Implementing Descriptors
The following methods only apply when an instance of the class containing the method (a so-called descriptorclass) appears in an owner class (the descriptor must be in either the owner’s class dictionary or in the class dictionary for one of its parents). In the examples below, “the attribute” refers to the attribute whose name is the key of the property in the owner class’
__dict__
.
object.
__get__
(self, instance, owner)Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or
None
when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise anAttributeError
exception.
object.
__set__
(self, instance, value)Called to set the attribute on an instance instance of the owner class to a new value, value.
object.
__delete__
(self, instance)Called to delete the attribute on an instance instance of the owner class.
object.
__set_name__
(self, owner, name)Called at the time the owning class owner is created. The descriptor has been assigned to name.
New in version 3.6.
The attribute
__objclass__
is interpreted by theinspect
module as specifying the class where this object was defined (setting this appropriately can assist in runtime introspection of dynamic class attributes). For callables, it may indicate that an instance of the given type (or a subclass) is expected or required as the first positional argument (for example, CPython sets this attribute for unbound methods that are implemented in C).3.3.2.3. Invoking Descriptors
In general, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol:
__get__()
,__set__()
, and__delete__()
. If any of those methods are defined for an object, it is said to be a descriptor.The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance,
a.x
has a lookup chain starting witha.__dict__['x']
, thentype(a).__dict__['x']
, and continuing through the base classes oftype(a)
excluding metaclasses.However, if the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined and how they were called.
The starting point for descriptor invocation is a binding,
a.x
. How the arguments are assembled depends ona
:Direct Call
- The simplest and least common call is when user code directly invokes a descriptor method:
Instance Bindingx.__get__(a)
.- If binding to an object instance,
Class Bindinga.x
is transformed into the call:type(a).__dict__['x'].__get__(a,type(a))
.- If binding to a class,
Super BindingA.x
is transformed into the call:A.__dict__['x'].__get__(None, A)
.- If
a
is an instance ofsuper
, then the bindingsuper(B, obj).m()
searchesobj.__class__.__mro__
for the base classA
immediately precedingB
and then invokes the descriptor with the call:A.__dict__['m'].__get__(obj, obj.__class__)
.For instance bindings, the precedence of descriptor invocation depends on the which descriptor methods are defined. A descriptor can define any combination of
__get__()
,__set__()
and__delete__()
. If it does not define__get__()
, then accessing the attribute will return the descriptor object itself unless there is a value in the object’s instance dictionary. If the descriptor defines__set__()
and/or__delete__()
, it is a data descriptor; if it defines neither, it is a non-data descriptor. Normally, data descriptors define both__get__()
and__set__()
, while non-data descriptors have just the__get__()
method. Data descriptors with__set__()
and__get__()
defined always override a redefinition in an instance dictionary. In contrast, non-data descriptors can be overridden by instances.Python methods (including
staticmethod()
andclassmethod()
) are implemented as non-data descriptors. Accordingly, instances can redefine and override methods. This allows individual instances to acquire behaviors that differ from other instances of the same class.The
property()
function is implemented as a data descriptor. Accordingly, instances cannot override the behavior of a property.3.3.2.4. __slots__
__slots__ allow us to explicitly declare data members (like properties) and deny the creation of __dict__ and __weakref__ (unless explicitly declared in __slots__ or available in a parent.)
The space saved over using __dict__ can be significant.
object.
__slots__
This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. __slots__ reserves space for the declared variables and prevents the automatic creation of __dict__ and __weakref__ for each instance.
3.3.2.4.1. Notes on using __slots__
- When inheriting from a class without __slots__, the __dict__ and __weakref__ attribute of the instances will always be accessible.
- Without a __dict__ variable, instances cannot be assigned new variables not listed in the __slots__definition. Attempts to assign to an unlisted variable name raises
AttributeError
. If dynamic assignment of new variables is desired, then add'__dict__'
to the sequence of strings in the __slots__ declaration.- Without a __weakref__ variable for each instance, classes defining __slots__ do not support weak references to its instances. If weak reference support is needed, then add
'__weakref__'
to the sequence of strings in the __slots__ declaration.- __slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.
- The action of a __slots__ declaration is not limited to the class where it is defined. __slots__ declared in parents are available in child classes. However, child subclasses will get a __dict__ and __weakref__unless they also define __slots__ (which should only contain names of any additional slots).
- If a class defines a slot also defined in a base class, the instance variable defined by the base class slot is inaccessible (except by retrieving its descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this.
- Nonempty __slots__ does not work for classes derived from “variable-length” built-in types such as
int
,bytes
andtuple
.- Any non-string iterable may be assigned to __slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.
- __class__ assignment works only if both classes have the same __slots__.
- Multiple inheritance with multiple slotted parent classes can be used, but only one parent is allowed to have attributes created by slots (the other bases must have empty slot layouts) - violations raise
TypeError
.