Adding methods to a class

A class decorator can create new methods using a two-step process. First, it must create a method function and then insert it into the class definition. This is often better done via a mixin class than a decorator. The obvious and expected use of a mixin is to insert methods. Inserting methods with a decorator is less obvious and can be astonishing to people reading the code and trying to find where the methods of a class are defined.

In the example of the Total_Ordering decorator, the exact method functions inserted were flexible and depended on what was already provided. This was a kind of special case that doesn't tend to astonish people reading the code.

We'll look at a technique to create a snapshot of an object's state by creating a text memento of the object. This can be implemented via a standardized memento() method. We'd like to include this standard method function in a variety of classes. First, we'll look at a decorator implementation. After that, we'll look at a mixin version of this design.

The following is the decorator version of adding this standardized memento() method:

def memento(class_: Type) -> Type:

def memento_method(self):
return f"{self.__class__.__qualname__}(**{vars(self)!r})"

class_.memento = memento_method
return class_

This decorator includes a method function definition that is inserted into the class. The vars(self) expression exposes the instance variables usually kept the internal __dict__ attribute of an instance. This produces a dictionary that can be included in the output string value.

The following is how we use this @memento decorator to add the memento() method to a class:

@memento
class StatefulClass:

def __init__(self, value: Any) -> None:
self.value = value

def __repr__(self) -> str:
return f"{self.value}"

The decorator incorporates a new method, memento(), into the decorated class. Here's an example of using this class and extracting a memento that summarizes the state of the object:

>>> st = StatefulClass(2.7)
>>> print(st.memento())
StatefulClass(**{'value': 2.7})

This implementation has the following disadvantages:

  • We can't override the implementation of the memento() method function to handle special cases. It's built into the class after the definition.
  • We can't extend the decorator function easily. Doing this would involve creating either a very complex memento() method, or perhaps some other unwieldy design to incorporate some kind of plug-in feature.

An alternative is to use a mixin class. Variations on this class allow customization. The following is the mixin class that adds a standard method:

class Memento:

def memento(self) -> str:
return (
f"{self.__class__.__qualname__}"
f"(**{vars(self)!r})"
)

The following is how we use this Memento mixin class to define an application class:

class StatefulClass2(Memento):

def __init__(self, value):
self.value = value

def __repr__(self):
return f"{self.value}"

The mixin provides a new method, memento(); this is the expected, typical purpose of a mixin. We can more easily extend the Memento mixin class to add features. In addition, we can override the memento() method function to handle special cases.

Now, let's see how to use decorators for security.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset