Skip to main content
deleted 2 characters in body
Source Link
Yohann O.
  • 134
  • 1
  • 4

A complement to the answer given by @Majo :

It is possible to create a class-based decorator that has the intended behavior without having to touch the __new__() method.

class decorator_with_argument: def __init__(self, *args, **kwargs): print("init:", [args, kwargs]) if (len(args) > 0) and callable(args[0]): self.wrapped_call = args[0] self.args = args[1:] else: self.wrapped_call = None self.args = args self.kwargs = kwargs def __call__(self, *args, **kwargs): print(["call"call:", [args, kwargs, self.wrapped_call]]wrapped_call]) if isinstance(self.wrapped_call, type(None)): new_instance = super().__new__(type(self)) new_instance.__init__( *([*args] + [*self.args]), **{**kwargs, **self.kwargs} ) return new_instance else: return self.wrapped_call(*args, **kwargs) 

If written this way, the decorator will record the arguments and create a callable class instance, which will in turn record supplementary arguments and return a callable class instance, until the first argument of the call is itself a callable (the decorated function).

This enables things like:

@decorator_with_argument def test(v): print(v) @decorator_with_argument(k=1) def test(v): print(v) @decorator_with_argument(K=1, l=2) def test(v): print(v) @decorator_with_argument(k=1)(l=2) def test(v): print(v) 

For the last example, you should be able to find the values of k and l in test.kwargs.

A complement to the answer given by @Majo :

It is possible to create a class-based decorator that has the intended behavior without having to touch the __new__() method.

class decorator_with_argument: def __init__(self, *args, **kwargs): print("init:", [args, kwargs]) if (len(args) > 0) and callable(args[0]): self.wrapped_call = args[0] self.args = args[1:] else: self.wrapped_call = None self.args = args self.kwargs = kwargs def __call__(self, *args, **kwargs): print(["call:", [args, kwargs, self.wrapped_call]]) if isinstance(self.wrapped_call, type(None)): new_instance = super().__new__(type(self)) new_instance.__init__( *([*args] + [*self.args]), **{**kwargs, **self.kwargs} ) return new_instance else: return self.wrapped_call(*args, **kwargs) 

If written this way, the decorator will record the arguments and create a callable class instance, which will in turn record supplementary arguments and return a callable class instance, until the first argument of the call is itself a callable (the decorated function).

This enables things like:

@decorator_with_argument def test(v): print(v) @decorator_with_argument(k=1) def test(v): print(v) @decorator_with_argument(K=1, l=2) def test(v): print(v) @decorator_with_argument(k=1)(l=2) def test(v): print(v) 

For the last example, you should be able to find the values of k and l in test.kwargs.

A complement to the answer given by @Majo :

It is possible to create a class-based decorator that has the intended behavior without having to touch the __new__() method.

class decorator_with_argument: def __init__(self, *args, **kwargs): print("init:", [args, kwargs]) if (len(args) > 0) and callable(args[0]): self.wrapped_call = args[0] self.args = args[1:] else: self.wrapped_call = None self.args = args self.kwargs = kwargs def __call__(self, *args, **kwargs): print("call:", [args, kwargs, self.wrapped_call]) if isinstance(self.wrapped_call, type(None)): new_instance = super().__new__(type(self)) new_instance.__init__( *([*args] + [*self.args]), **{**kwargs, **self.kwargs} ) return new_instance else: return self.wrapped_call(*args, **kwargs) 

If written this way, the decorator will record the arguments and create a callable class instance, which will in turn record supplementary arguments and return a callable class instance, until the first argument of the call is itself a callable (the decorated function).

This enables things like:

@decorator_with_argument def test(v): print(v) @decorator_with_argument(k=1) def test(v): print(v) @decorator_with_argument(K=1, l=2) def test(v): print(v) @decorator_with_argument(k=1)(l=2) def test(v): print(v) 

For the last example, you should be able to find the values of k and l in test.kwargs.

Source Link
Yohann O.
  • 134
  • 1
  • 4

A complement to the answer given by @Majo :

It is possible to create a class-based decorator that has the intended behavior without having to touch the __new__() method.

class decorator_with_argument: def __init__(self, *args, **kwargs): print("init:", [args, kwargs]) if (len(args) > 0) and callable(args[0]): self.wrapped_call = args[0] self.args = args[1:] else: self.wrapped_call = None self.args = args self.kwargs = kwargs def __call__(self, *args, **kwargs): print(["call:", [args, kwargs, self.wrapped_call]]) if isinstance(self.wrapped_call, type(None)): new_instance = super().__new__(type(self)) new_instance.__init__( *([*args] + [*self.args]), **{**kwargs, **self.kwargs} ) return new_instance else: return self.wrapped_call(*args, **kwargs) 

If written this way, the decorator will record the arguments and create a callable class instance, which will in turn record supplementary arguments and return a callable class instance, until the first argument of the call is itself a callable (the decorated function).

This enables things like:

@decorator_with_argument def test(v): print(v) @decorator_with_argument(k=1) def test(v): print(v) @decorator_with_argument(K=1, l=2) def test(v): print(v) @decorator_with_argument(k=1)(l=2) def test(v): print(v) 

For the last example, you should be able to find the values of k and l in test.kwargs.