- Mastering Objectoriented Python
- Steven F. Lott
- 376字
- 2021-11-12 16:25:12
Using special methods for attribute access
We'll look at the three canonical special methods for attribute access: __getattr__()
, __setattr__()
, and __delattr__()
. Additionally, we'll acknowledge the __dir__()
method to reveal attribute names. We'll defer __getattribute__()
to the next section.
The default behavior shown in the first section is as follows:
- The
__setattr__()
method will create and set attributes. - The
__getattr__()
method will do two things. Firstly, if an attribute already has a value,__getattr__()
is not used; the attribute value is simply returned. Secondly, if the attribute does not have a value, then__getattr__()
is given a chance to return a meaningful value. If there is no attribute, it must raise anAttributeError
exception. - The
__delattr__()
method deletes an attribute. - The
__dir__()
method returns a list of attribute names.
The __getattr__()
method function is only one step in a larger process; it is only used if the attribute is otherwise unknown. If the attribute is a known attribute, this method is not used. The __setattr__()
and __delattr__()
methods do not have built-in processing. These methods don't interact with additional processing.
We have a number of design choices for controlling attribute access. These follow our three essential design choices to extend, wrap, or invent. The design choices are as follows:
- We can extend a class, making it almost immutable by overriding
__setattr__()
and__delattr__()
. We can also replace the internal__dict__
with__slots__
. - We can wrap a class and delegate attribute access to the object (or composite of objects) being wrapped. This may involve overriding all three of these methods.
- We can implement property-like behaviors in a class. Using these methods, we can assure that all property processing is centralized.
- We can create lazy attributes where the values aren't (or can't be) computed until they're needed. We may have an attribute that doesn't have a value until it's read from a file, database, or network. This is common use for
__getattr__()
. - We can have eager attributes, where setting an attribute creates values in other attributes automagically. This is done via overrides to
__setattr__()
.
We won't look at all of these alternatives. Instead, we'll focus on the two most commonly used techniques: extending and wrapping. We'll create immutable objects and look at other ways to eagerly compute attribute values.