Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending a class in Python inside a decorator

I am using a decorator to extend certain classes and add some functionality to them, something like the following:

def useful_stuff(cls):
  class LocalClass(cls):
    def better_foo(self):
      print('better foo')
  return LocalClass

@useful_stuff
class MyClass:
  def foo(self):
    print('foo')

Unfortunaltely, MyClass is no longer pickleable due to the non global LocalClass

AttributeError: Can't pickle local object 'useful_stuff.<locals>.LocalClass'
  • I need to pickle my classes. Can you recommend a better design?
  • Considering that there can be multiple decorators on a class, would switching to multiple inheritance by having MyClass inherit all the functionality be a better option?
like image 310
rohit-biswas Avatar asked Dec 16 '18 17:12

rohit-biswas


People also ask

How do you add a class to a decorator in Python?

To decorate a function with a class, we must use the @syntax followed by our class name above the function definition. Following convention, we will use camel-case for our class name. In the class definition, we define two methods: the init constructor and the magic (or dunder) call method.

How do you extend a decorator in Python?

Simply write the decorator name using the “@” symbol before the function definition as shown below. In the following script, the functionality of the my_func() function is extended using the my_decorator() function. Finally, you can also extend multiple functions using a single decorator.

Can you extend a class in Python?

In Python, we can extend a class to create a new class from the existing one. This becomes possible because Python supports the feature of inheritance. Using inheritance, we can make a child class with all the parent class's features and methods.

What is class decorator in Python?

Decorators are a very powerful and useful tool in Python since it allows programmers to modify the behaviour of function or class. Decorators allow us to wrap another function in order to extend the behaviour of the wrapped function, without permanently modifying it.

How to decorate a class in Python?

To decorate this class in Python, we can either add new methods to the class or modify the existing ones, or do both. Also, there are two ways of doing so in Python, either by using a function decorator or by using a class decorator. Let’s see an example of each one by one. Decorate Class using Function Decorator

How to add a decorator to add function in Python?

Now, we have to define a decorator in such a way that the add() function should also print the product of the numbers along with the sum. For this, we can create a decorator class. We can implement the __call__() method inside a class to implement the decorators.

How to use callable classes as decorators in Python?

Use callable classes as decorators by implementing the __call__ method. Pass the decorator arguments to the __init__ method. Did you find this tutorial helpful ?

How to decorate the class using a function decorator in Java?

To decorate the class using a function decorator accept the class as an argument, modify its code and return the class at the end. If the display method did not existed in the class, the newdisplay would have been added to the class as the display method.


1 Answers

You need to set the metadata so the subclass looks like the original:

def deco(cls):
    class SubClass(cls):
        ...
    SubClass.__name__ = cls.__name__
    SubClass.__qualname__ = cls.__qualname__
    SubClass.__module__ = cls.__module__
    return SubClass

Classes are pickled by using their module and qualname to record where to find the class. Your class needs to be found in the same location the original class would have been if it hadn't been decorated, so pickle needs to see the same module and qualname. This is similar to what funcutils.wraps does for decorated functions.

However, it would probably be simpler and less bug-prone to instead add the new methods directly to the original class instead of creating a subclass:

def better_foo(self):
    print('better_foo')

def useful_stuff(cls):
    cls.better_foo = better_foo
    return cls
like image 57
user2357112 supports Monica Avatar answered Oct 13 '22 21:10

user2357112 supports Monica