Programmer's Python - Default Methods
Written by Mike James   
Monday, 06 July 2020
Article Index
Programmer's Python - Default Methods
Customizing Delete And Dir
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

Is now available as a print book: Amazon

pythoncover


Contents

  1. Hello Python World
  2. Variables, Objects and Attributes
  3. The Function Object
      Extract - Function Objects
  4. Scope, Lifetime and Closure
      Extract - Local and Global
  5. Advanced Functions
      Extract -  Decorators 
  6. Class Methods and Constructors
  7. Inside Class
  8. Metaclass
  9. Advanced Attributes
      Extract - Properties
  10. Custom Attribute Access
      Extract -  Custom Attributes
      Extract -  Default Methods ***NEW
  11. Single Inheritance
  12. Multiple Inheritance
  13. Class and Type
      Extract - Class
  14. Type Annotation
      Extract - Type Annotation 
  15. More Magic - Operator Overloading

 

Advanced Attributes

The basics of custom attributes are covered in the first part of the chapter.

  • The Descriptor Object
  • Custom Attribute Access

 

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.



Last Updated ( Monday, 06 July 2020 )