Python装饰器采用额外的反模式参数



通过包装器向函数添加参数是python反模式吗?我想添加一个包装器,将许多函数的输出保存到一个位置,因此包装器似乎是有意义的。然而,Pycharm无法自动完成修饰函数的参数(https://intellij-support.jetbrains.com/hc/en-us/community/posts/360002754060-Autocomplete-with-arguments-for-decorated-functions)。

与使用包装器更改函数签名有关的一些讨论似乎表明这是一种糟糕的做法(https://youtrack.jetbrains.com/issue/PY-33688#focus=Comments-27-3268273.0-0(.

一些装饰器可以更改函数的签名,以便正确处理此类情况PyCharm必须读取装饰器的主体,但由于性能原因无法完成。

所以这样做会是反模式吗:

from functools import wraps
from typing import Callable
my_dict = {"very": {"deeply": {"nested": {"filepath": "hidden_filepath"}}}}

def decorator(function: Callable):
@wraps(function)
def wrapper(extra_arg: str, function_arg: str) -> str:
file_path: str = my_dict["very"]["deeply"]["nested"][extra_arg]
print(f"saving to: {file_path}")
result: str = function(function_arg)
print(f"result: {result}")
return result
wrapper.__doc__ += "/n:param extra_arg: an extra argument"
return wrapper

@decorator
def my_function(an_arg: str) -> str:
"""
my docstring
:param an_arg:
:return:
"""
print(f"my_function arg: {an_arg}")
return an_arg * 2

my_function("filepath", "cool_str")

我也不喜欢在函数中附加文档字符串,但我发现这是一个解决方案:签名更改装饰器:正确地记录额外的参数。仅仅更改修饰函数的docstring是否更有意义?

编辑:我能想到的唯一其他合理的解决方案是创建一个以另一个函数为自变量的函数,这就是包装器应该解决的问题,例如

def decorator(extra_arg:str, function: Callable, **kwargs)-> str:
file_path: str = my_dict["very"]["deeply"]["nested"][extra_arg]
print(f"saving to: {file_path}")
result: str = function(**kwargs)
print(f"result: {result}")
return result
def my_function(an_arg: str) -> str:
"""
my docstring
:param an_arg:
:return:
"""
print(f"my_function arg: {an_arg}")
return an_arg * 2
decorator("filepath", my_function, an_arg="cool_str")

考虑可维护性。

其他维护代码的人会发现my_function只有一个arg。PyCharm和mypy会尖叫,称使用多个arg调用my_function是错误的。然后其他人去"修复"所有的"bug"。

您的程序中断。

在发现装饰师更改了函数的签名之前,要进行数小时的故障排除。

见鬼,不需要成为别人。。。把你的代码放在一两个月后,当你回去的时候,你可能已经忘记了你的装饰师破坏了你的函数。。。

所以,是的,这是一种糟糕的做法,一种反模式,一种代码气味,一种<在这里插入你最喜欢的负面含义流行语>。

最新更新