class decorator with parameter in python, raises TypeError: missing 1 required positional argument: 'type'

75 Views Asked by At

The following code:

    def myDecorator(cls, type):
        class wrapper(cls):
            contaVarClasse = 0

            def __init__(cls, *args, **kwargs):
                for value in cls.__dict__.values():
                    if isinstance(value, type):
                        cls.contaVarClasse += 1
                print(cls.__dict__)

        return wrapper

    @myDecorator(str)
    class MyClass:
        countme = "b"
        notme = 2
        def __init__(self):
            dontcountme = "a"
            norme = 5

    print(MyClass.contaVarClasse)

raises the "TypeError: missing 1 required positional argument: 'type'" error

From my knowledge, @myDecorator(str) should be equal MyClass = myDecorator(MyClass, str), but I'm clearly wrong and I've been pretty much unable to find what I did wrong so far.

After 40 minutes of googling "decorators with parameters" and "class decorator with parameters" and "TypeError: missing 1 required positional decorator", I just found all of the questions and answers to be related to decorators being applied to classes' methods, and nobody actually trying to decorate a class with another class.

The class decorator "myDecorator" should decorate MyClass with a variable (contaVarClasse) that should count how many class variables of type type in the decorated class there are.

1

There are 1 best solutions below

2
On

If you want to be able to configure a decorator with a call like @myDecorator(str) you should make myDecorator a decorator factory that returns a decorator instead:

def decorator_factory(type_):
    def decorator(cls):
        cls.contaVarClasse = sum(
            isinstance(value, type_)
            for name, value in vars(cls).items()
            if not (name.startswith('__') and name.endswith('__'))
        )
        return cls
    return decorator

so that:

@decorator_factory(str)
class MyClass:
    countme = "b"
    notme = 2

    def __init__(self):
        self.dontcountme = "a"
        self.norme = 5

print(MyClass.contaVarClasse)

outputs:

1

Demo: https://ideone.com/QRaW4E