- Mastering Objectoriented Python
- Steven F. Lott
- 305字
- 2021-11-12 16:25:14
Note
The __getattribute__()
method cannot give any simple self.name
attribute access; it will lead to infinite recursions.
In order to get attribute values within the __getattribute__()
method, we must explicitly refer to the base method defined in object
, as shown in the following declaration:
object.__getattribute__(self, name)
We could, for example, revise our immutable class to use __getattribute__()
and prevent access to the internal __dict__
attribute. The following is a class that conceals all the names beginning with the underscore character (_
):
class BlackJackCard3: """Abstract Superclass""" def __init__( self, rank, suit, hard, soft ): super().__setattr__( 'rank', rank ) super().__setattr__( 'suit', suit ) super().__setattr__( 'hard', hard ) super().__setattr__( 'soft', soft ) def __setattr__( self, name, value ): if name in self.__dict__: raise AttributeError( "Cannot set {name}".format(name=name) ) raise AttributeError( "'{__class__.__name__}' has no attribute '{name}'".format( __class__= self.__class__, name= name ) ) def __getattribute__( self, name ): if name.startswith('_'): raise AttributeError return object.__getattribute__( self, name )
We've overridden __getattribute__()
to raise an attribute error on private names as well as Python's internal names. This has a microscopic advantage over the previous example: we are not allowed to tweak the object at all. We'll see an example of an interaction with an instance of this class.
The following is an example of an object of this class being mutated:
>>> c = BlackJackCard3( 'A', '♠', 1, 11 ) >>> c.rank= 12 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 9, in __setattr__ File "<stdin>", line 13, in __getattribute__ AttributeError >>> c.__dict__['rank']= 12 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 13, in __getattribute__ AttributeError
As general advice, it's rarely a good idea to mess with __getattribute__()
. The default method is quite sophisticated, and almost everything we need is available as a property or as a change to __getattr__()
.