Decorators with parameters?
The syntax for decorators with arguments is a bit different - the decorator with arguments should return a function that will take a function and return another function. So it should really return a normal decorator. A bit confusing, right? What I mean is:
def decorator_factory(argument):
def decorator(function):
def wrapper(*args, **kwargs):
funny_stuff()
something_with_argument(argument)
result = function(*args, **kwargs)
more_funny_stuff()
return result
return wrapper
return decorator
Here you can read more on the subject - it's also possible to implement this using callable objects and that is also explained there.
Python decorators with arguments
It is just another level of indirection, basically the code is equivalent to:
decorator = my_function("Name ")
decorated = decorator(text)
text = decorated
Without arguments, you already have the decorator, so
decorated = my_function(text)
text = decorated
Typing decorators that can be used with or without arguments
The issue comes from the first overload (I should have read the pyright
message twice!):
@overload
def decorator(arg: F) -> F:
...
This overload accepts a keyword parameter named arg
, while the implementation does not!
Of course this does not matter in the case of a decorator used with the @decorator
notation, but could if it is called like so: fct2 = decorator(arg=fct)
.
Python >= 3.8
The best way to solve the issue would be to change the first overload so that arg
is a positional-only parameter (so cannot be used as a keyword argument):
@overload
def decorator(arg: F, /) -> F:
...
With support for Python < 3.8
Since positional-only parameters come with Python 3.8, we cannot change the first overload as desired.
Instead, let's change the implementation to allow for a **kwargs
parameter (an other possibility would be to add a keyword arg
parameter). But now we need to handle it properly in the code implementation, for example:
def decorator(*args: Any, **kwargs: Any) -> Any:
if kwargs:
raise TypeError("Unexpected keyword argument")
# rest of the implementation here
Default arguments in a function when using decorators
In this case **kwargs
is not about the function signature, it's about how you called it.
And your call
simple(10)
have only specified one positional argument.
Decorator (wrapper) knows nothing about the function and its default arguments.
It just passes the arguments it received further.
simple(*(10,), **{})
If you want to do some excercise and write decorator that is informed about the defaults of a function it is wrapping, I suggest to take a look at inspect.signature()
.
python decorator how to add parameters
You need a decorator factory, that is a function that returns the decorator:
from functools import wraps
def round_decimal(n):
def decorator(fn):
@wraps(fn)
def inner(*args, **kwargs):
return round(fn(*args, **kwargs), n)
return inner
return decorator
@round_decimal(3)
def func(a, b, c):
return a / b / c
print(func(1.33333, 3.44444, 4.555))
output:
0.085
Related Topics
What Is the Eafp Principle in Python
How to Create a Tuple With Only One Element
Using @Property Versus Getters and Setters
Unicodedecodeerror When Reading CSV File in Pandas With Python
Is Explicitly Closing Files Important
How to Fix: "Unicodedecodeerror: 'Ascii' Codec Can't Decode Byte"
How to Read CSV Data into a Record Array in Numpy
"Large Data" Workflows Using Pandas
Open Web in New Tab Selenium + Python
How to Add a New Column to an Existing Dataframe
Saving Utf-8 Texts With Json.Dumps as Utf8, Not as \U Escape Sequence
How to Add Hovering Annotations to a Plot