Home > Software engineering >  Is there a DRY rule regarding decorators?
Is there a DRY rule regarding decorators?

Time:12-20

I was under the impression that if you use two or more of the same kind of decorator methods in a row such as @classmethod in a class, you don't have to use @classmethod twice (DRY principle).

For example, if you use @classmethod and the next method defined in the class also has cls as the first implicit argument, then Python's interpreter should know that the second method is also a class method.

class Cat:
    holiness = 100
    luck = 100
    
    @classmethod
    def more_holiness(cls):
        cls.holiness  = 1

    def more_luck(cls):
        cls.luck  = 1

Cat.more_holiness() # Works fine.
Cat.more_luck() # Error outputted. Expected one argument.

How would I write this code without having to use @classmethod twice?

Expected both methods to be class methods, got an unexpected result.

CodePudding user response:

A decorator can only decorate one function or class at a time. For your purpose, you can create a class decorator instead to decorate all non-dunder methods with classmethod:

def classmethods(cls):
    for name, obj in vars(cls).items():
        if callable(obj) and not name.startswith('__'):
            setattr(cls, name, classmethod(obj))
    return cls

so that:

@classmethods
class Cat:
    holiness = 100
    luck = 100

    def more_holiness(cls):
        cls.holiness  = 1

    def more_luck(cls):
        cls.luck  = 1

Cat.more_holiness()
Cat.more_luck()
print(Cat.holiness)
print(Cat.luck)

Outputs:

101
101

Demo: https://replit.com/@blhsing/ImmaculateThisMicrokernel

CodePudding user response:

As the other answer and the comments have already pointed out, decorators in Python don't work that way. Decorators are simple function calls that act on the following declaration (either a class or a function declaration). They are not a form of state that affects future declarations in the same scope.

More broadly, you're misunderstanding the DRY principle. DRY, short for "don't repeat yourself", is paraphrased thusly according to Wikipedia:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system

It says nothing about repeating individual lines of code. A single @classmethod declaration being repeated is not a violation of DRY. Indeed, several three-line functions that do similar computations is not a violation of DRY; I often see (and write) code that behaves that way. Sometimes it makes sense to add an abstraction layer, and sometimes it doesn't.

The DRY principle is about data, not lines of code. If my program is modelling properties of a spacecraft, then, for example, there should be one class somewhere that encapsulates the craft's target interior temperature. If I have four different classes that are all simultaneously trying to monitor the temperature, then that is a violation of DRY, since none of those classes can reasonably say that they're the "authoritative" representation of that information.

  • Related