Page 1 of 2 Custom attribute access - wonderful but what is it for? You can find out how to implement default methods and more in this extract from my book on Python objects.
Programmer's Python Everything is an Object Second Edition
Is now available as a print book: Amazon
Contents
- Get Ready For The Python Difference
- Variables, Objects and Attributes
- The Function Object
- Scope, Lifetime and Closure
Extract 1: Local and Global ***NEW!
- Advanced Functions
- Decorators
- Class, Methods and Constructors
Extract 1: Objects Become Classes
- Inside Class
- Meeting Metaclasses
- Advanced Attributes
- Custom Attribute Access
- Single Inheritance
- Multiple Inheritance
- Class and Type
- Type Annotation
- Operator Overloading
- Python In Visual Studio Code
Extracts from the first edition
<ASIN:1871962749>
<ASIN:1871962595>
<ASIN:1871962765>
The basics of custom attributes are covered in the first part of the chapter.
Customizing Assignment __setattr__
So far we have only looked at getting attributes.
The other side of the coin is setting attributes. In this case things are simpler as there is a single magic method called __setattr__ which is called every time you attempt an assignment to an attribute:
__setattr__(self, item, value)
self is the instance, item is the attribute and value is the value you are attempting to set it to.
Notice that there is no need for a magic method that is called when assignment fails because of the Python rule that if an attribute doesn’t exist then it should be created.
Notice that as __setattr__ is always called for an assignment it is very easy to create an infinite recursion:
class MyClass:
myAttribute1=42
def __setattr__(self, item, value):
self.myAttribute1 =value
myObj=MyClass()
myObj.myAttribute1=43
print(myObj.myAttribute1)
When you try to assign 43 to myAttribute1 __setattr__ is called and it attempts to assign 43 to myAttribute1 and an infinite recursion is started.
The recommended way to set attributes in __setattr__ is to use the superclass’s __setattr__.
For example:
class MyClass:
myAttribute1=42
def __setattr__(self, item, value):
super().__setattr__(item, value)
As with most of the magic methods, __setattr__ defined in a class is called when assignments are made to attributes of an instance of the class but not for assignments made to attributes of the class.
As usual if you want to handle assignments to attributes of the class you have to define __setattr__ in the metaclass:
class MyMeta(type):
def __setattr__(self, item, value):
super().__setattr__(item, value)
and you have to remember to set the metaclass:
class MyClass(metaclass=MyMeta):
Following this any assignments to the class attributes will call the __setattr__ defined in the metaclass:
MyClass.myAttribute1=43
The setattr built-in function:
setattr(object,item,value)
also calls __setattr__ and so can lead to infinite recursion.
Default Methods
When programmers first meet Python’s custom attribute, access the tendency is to be impressed and then wonder what you can use it for. It is worth pointing out, again, that attributes can be any Python object which means they can be functions.
One of the more interesting ideas is that a class can define a default method.
For example:
class MyClass:
def __getattr__(self, item):
def default():
print(item)
print(self)
return default
If the attribute isn’t found then __getattr__ is called and this returns a function. Notice that this function has access to item and self due to closure – so it is a method but one that is early bound to the instance. Also notice that this creates a new function object every time the attribute is accessed – a much better idea is to define the function outside of __getattr__ and forgo the benefits of closure.
For example:
myObj=MyClass()
myObj.myMethod()
calls default with item set to myMethod and self set to myObj.
If the method isn’t executed at once you can see that it is bound to the instance:
temp=myObj.myMethod
temp()
item is still set to myMethod and self set to myObj.
|