avatarStephen Fordham

Summary

The provided web content discusses the use of method decorators in Python classes to enhance functionality, such as data integrity checks or logging, with a focus on a specific example using an integer_check decorator to ensure attributes are integers.

Abstract

The article "Decorating Methods defined in a Class With Python" delves into the practical application of decorators within class methods in Python. It emphasizes the versatility of decorators in extending the capabilities of methods, such as performing data validation or executing additional operations. The author illustrates this concept through a detailed example involving a NumericalOps class, which includes methods for multiplying and exponentiating numbers. A custom integer_check decorator is implemented to confirm that the method arguments are integers, thereby ensuring data integrity. The article further explores how the same decorator can be adapted and reused across multiple methods within the class, demonstrating the decorator's flexibility and utility in Python programming.

Opinions

  • The author believes that decorators are an elegant solution for extending method functionality in Python classes.
  • The use of decorators for input validation is presented as a practical and efficient approach to maintaining data integrity.
  • The article suggests that decorators can be designed to be versatile, allowing for their application across various methods within a class.
  • The author implies that while the examples provided are simple, the principles behind them can be applied to more complex scenarios in Python programming.
  • The author values the readability and maintainability of code, as evidenced by the emphasis on using decorators to make the code more concise and understandable.

Decorating Methods defined in a Class With Python

Method decorators in a class

Image Courtesy of Roselyn Tirado via Unsplash

Decorating Methods

Decorators provide a convenient and elegant way to add functionality to functions and methods in Python. Decorators can be implemented in a number of different ways. One useful use-case for decorators involves using them with methods defined in a class. Decorating methods in the classes we create can extend the functionality of the defined method. For example, we could implement a data integrity check, or write the output of the method call to a file. It really is up to us what we choose to do. Method decorators simply provide us with the facility to extend functionality in an elegant way.

As always, the use of decorators with methods will be best demonstrated using an example.

In the example below, I have created a simple class called NumericalOps, which requires 2 arguments, val1, and val2. In the init constructor, these arguments get set as attributes in the object. Next, I have 2 methods defined in this class, namely, multiply_together and power.

Lets proposed the rather trivial and contrived scenario. I would like the two attributes, val1 and val2 set in the object to be numerical integers. The multiply_together method simply multiplies the two values together and returns the value from this operation. Importantly, in Python, it is possible to multiple a string, for example by an integer. This is demonstrated when we create an instance of the NumericalOps class, x, and pass in the two arguments, 2 and ‘my_string’, as shown in the console output in the example below.

To provide data input integrity, a decorator can be used to decorate a method defined in the class. Currently, in the example, the decorator, @integer_check is commented out.

To provide data integrity, I will write a decorator, named interger_check. To decorate a method in a class, first use the ‘@’ symbol followed by the name of the decorator function.

A decorator is simply a function that takes a function as an argument and returns yet another function. Here, when we decorate, multiply_together with integer_check, the integer function gets called. The multiply_together method gets passed as the argument to the integer_check function and returns inner. The local inner function then gets called, which takes the object which we call ref, and checks the attributes using the isinstance function. If a non-integer type gets passed, for example, ‘my_string’, a TypeError exception gets raised, and a message is the output to the console instructing the user where they went wrong. If both arguments are however integers, inner returns the original method with the object passed as an argument.

The source code for this example can be found on my GitHub page, here and below.

Using the Same Decorator for Multiple Methods

To increase both the usability and the utility of decorators, we can design their implementation to be used with multiple methods.

Again, this is best illustrated with an example, so let's build on the example from the previous section.

Let's propose, that I would also like the integer_check decorator to validate that the exponent we use in the power method is also an integer. That makes logical sense, because when we call the power method, it simply calls the multiply_together method, and multiplies the return value of this method by the exponent. In each case, therefore, I need to make sure that val1, val2 and the exponent are integers.

To implement this behaviour, I make an alteration to the integer_check decorator. I simply set a default argument to the expo parameter in the local inner function defined inside the decorator. Now, if we call the power method on our instance, y, inner will be returned and then subsequently called with both the object which we notate in the inner definition as ref, and the expo value.

In the conditional block, if expo is passed, we check its type using the isinstance function, raise an error if it is not an integer, or return the method, with the object and the exponent if the exponent and val1 and val2 are all integers.

Usefully, we can still use the integer_check decorator on the multiply_together method, because a default value of None has been set for expo.

Now, we have a decorator which can perform user input validation across multiple methods in our class.

With integers as input, we get the expected behaviour in our console output.

With erroneous input (non-integer types), we get a helpful instructive error message.

The source code for this example can be found here.

Summary

Of course, as always, the examples presented are rather trivial and contrived. There are other ways to implement the behaviour seen here, without the requirement for decorators. My intention here is to demonstrate how decorators work, and how they could be incorporated into your code design. For those interested, I have also written another two tutorials detailing how decorators can be used to decorate functions, and how the decorator itself can be a class. The links to these two articles can be found by accessing the links.

Programming
Data Science
Coding
Towards Data Science
Python
Recommended from ReadMedium