1

I am trying to create decorator for classes which takes parent_klass as an argument and modifies original class by inheriting parent_klass and returns it. See below implementation of this idea:

class HelperClass:
    def helper_method(self):
        print("helper method...")


def inherit_from(parent_klass):

    def wrapper(cls):
        class DecoratedClass(cls, parent_klass):
            pass
        return DecoratedClass

    return wrapper


@inherit_from(HelperClass)
class Foo:
    pass


f = Foo()
f.helper_method()  # prints helper method...
print(Foo.__name__)  # prints DecoratedClass

Above code works as I expected except the last print line. My problem is that __name__ attribute of original class (Foo) is not preserved and replaced by DecoratedClass. How can I apply functools.wraps functionality in this case? Is there any other way than using wraps function?

EDIT: Actually, I want to use this decorate in Django project, in which __name__ attribute is important for database mapping. This decorator is intended to generate dynamic models that also contains custom managers. Simply inheriting the class without decorator does not solve my problem, since supplied argument ('parent_klass' in this case, but 'custom queryset' class in actual implemetation), is also used in bases class's (Foo) methods.

Elgin Cahangirov
  • 1,932
  • 4
  • 24
  • 45
  • 1
    What would be the advantage of your approach over the normal inheritance? – Klaus D. Jan 13 '20 at 19:33
  • In this case, there is no advantage. But this is just a simple example for illustrating the problem. I will use it in other context that I can't use inheritance since multi-level composition exists. – Elgin Cahangirov Jan 13 '20 at 19:38
  • That does not sound convincing. Especially not when your class returned by the decorator uses inheritance. – Klaus D. Jan 13 '20 at 19:42
  • Does this answer your question? [functools.wraps equivalent for class decorator](https://stackoverflow.com/questions/28622235/functools-wraps-equivalent-for-class-decorator) – kaya3 Jan 13 '20 at 19:45
  • @KlausD. what does not convince you? Running above script outputs "DecoratedClass" to the console. Do you need hundreds line of code for convince? In essence, my problem is as shown in above attached few lines of code. – Elgin Cahangirov Jan 13 '20 at 19:48
  • 1
    `@inherit_from(HelperClass)` is a really strange decorater, it appears to do nothing that simply `class Foo(HelperClass)` could do, with no discernible benefit. I'm not sure what "multi-level composition" is, nor how it would prevent regular inheritance, but anyway, take a look at https://stackoverflow.com/a/9541560/5014455 – juanpa.arrivillaga Jan 13 '20 at 19:51
  • @ElginCahangirov I believe Klaus means that he is not convinced the problem is a useful one to solve. Really you are just looking for a way to write a class decorator which preserves the name (and perhaps other things such as the doc string) of the decorated class, and Klaus is commenting that the actual decorator you gave as an example is not a very useful decorator. – kaya3 Jan 13 '20 at 19:53
  • As @kaya3 pointed out already, you could use `type()` and get really weird with it if you wanted to. – haliphax Jan 14 '20 at 07:10

0 Answers0