python - 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")
我也不喜欢在函数中附加到文档字符串,但发现这是一个解决方案:签名更改装饰器:正确记录附加参数。只更改装饰函数的文档字符串会更有意义吗?
编辑:我能想到的唯一其他合理的解决方案是创建一个将另一个函数作为参数的函数,这是包装器应该解决的问题,例如。
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 并会尖叫使用多个 argmypy
调用是错误的。my_function
然后其他人去“修复”所有“错误”。
你的程序中断了。
在发现您的装饰器更改了函数的签名之前,进行了数小时的故障排除。
哎呀,不需要是其他人...将您的代码保留一两个月,当您返回时,您可能会忘记您的装饰器破坏了您的功能...
所以,是的,这是一种不好的做法,一种反模式,一种代码味道,一种<在此处插入你最喜欢的负面含义流行语>。
推荐阅读
- angular - Angular 9 - 组件输入和输出性能调优
- url - 使用 Mac 终端将十六进制代码转换为 URL 中的 ASCII 字符
- javascript - 更改类中所有元素的背景
- android - SDK39 上未处理的承诺拒绝 - SplashScreen
- css - typecipt CSS.Properties 重叠属性
- multithreading - 从不同线程和同一个线程调用 QObject 方法的首选方式
- javascript - Javascript 新语法的 Webpack 加载器
- hyperledger-fabric - Hyperledger Fabric 节点 SDK 服务器部署
- android - 在下载文件夹的应用程序特定目录中重新安装时保留文件
- selenium - 使用 pyinstaller 将 .py 转换为 .exe 后,带有代理的 Selenium 脚本不起作用