[英]Best practice to rename a method parameter in a deployed Python module
Say I maintain a Python module with some method foo()
:假设我使用一些方法foo()
维护一个 Python 模块:
def foo(BarArg=None, AnotherArg=False):
return True
But now I'm not satisfied with the PascalCase of my argument names, and would like to rename them as such:但是现在我对我的参数名称的 PascalCase 不满意,并且想这样重命名它们:
def foo(bar_arg=None, another_arg=False):
...
How can I introduce this change without breaking existing client code?如何在不破坏现有客户端代码的情况下引入此更改?
I wouldn't really want deprecation warnings (but maybe that's the best practice), and also would very much would like to keep my function's name...我真的不想要弃用警告(但也许这是最佳实践),并且也非常想保留我的函数名称......
For now, **kwargs
plus some input validation logic is the only solution that comes to mind, but it seems like the wrong direction.目前, **kwargs
加上一些输入验证逻辑是唯一想到的解决方案,但它似乎是错误的方向。
You can use a decorator factory to intercept any uses of the incorrect args:您可以使用装饰器工厂来拦截对不正确参数的任何使用:
def re_arg(kwarg_map):
def decorator(func):
def wrapped(*args, **kwargs):
new_kwargs = {}
for k, v in kwargs.items():
if k in kwarg_map:
print(f"DEPRECATION WARNING: keyword argument '{k}' is no longer valid. Use '{kwarg_map[k]}' instead.")
new_kwargs[kwarg_map.get(k, k)] = v
return func(*args, **new_kwargs)
return wrapped
return decorator
# change your kwarg names as desired, and pass the kwarg re-mapping to the decorator factory
@re_arg({"BarArg": "bar_arg", "AnotherArg": "another_arg"})
def foo(bar_arg=None, another_arg=False):
return True
Demo:演示:
In [7]: foo(BarArg="hello")
DEPRECATION WARNING: keyword argument 'BarArg' is no longer valid. Use 'bar_arg' instead.
Out[7]: True
In [8]: foo(AnotherArg="hello")
DEPRECATION WARNING: keyword argument 'AnotherArg' is no longer valid. Use 'another_arg' instead.
Out[8]: True
In [9]: foo(x="hello") # still errors out on invalid kwargs
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [9], line 1
----> 1 foo(x="hello")
Cell In [4], line 9, in re_arg.<locals>.wrapped(**kwargs)
7 print(f"DEPRECATION WARNING: keyword argument '{k}' is no longer valid. Use '{kwarg_map[k]}' instead.")
8 new_kwargs[kwarg_map.get(k, k)] = v
----> 9 return func(**new_kwargs)
TypeError: foo() got an unexpected keyword argument 'x'
In [10]: foo(another_arg="hello") # no warning if you pass a correct arg (`bar_arg` has a default so it doesn't show up in `new_kwargs`.
Out[10]: True
In [11]: foo(BarArg="world", AnotherArg="hello")
DEPRECATION WARNING: keyword argument 'BarArg' is no longer valid. Use 'bar_arg' instead.
DEPRECATION WARNING: keyword argument 'AnotherArg' is no longer valid. Use 'another_arg' instead.
Out[11]: True
You could get super fancy and leave in the old kwargs alongside the new ones, inspect the signature, extract the old kwargs and build the kwarg_map
dynamically, but that'd be quite a bit more work for probably not much gain in my opinion, so I'll "leave it as an exercise for the reader".您可能会非常喜欢,将旧的 kwargs 与新的 kwargs 一起留下,检查签名,提取旧的 kwargs 并动态构建kwarg_map
,但在我看来,这可能需要做更多的工作,可能不会有太大的收获,所以我将“把它作为练习留给读者”。
Another solution would be to simply add a new_foo
function, transfer the old foo
implementation over, and simply call new_foo
from foo
with the kwarg re-mapping shown above, and with a deprecation warning, but I think this is cleaner than having to maintain a bunch of stubs.另一种解决方案是简单地添加一个new_foo
function,将旧的foo
实现转移过来,然后使用上面显示的 kwarg 重新映射简单地从foo
调用new_foo
,并带有弃用警告,但我认为这比必须维护一个更干净一堆存根。
You may also want to check out the deprecation
library: https://pypi.org/project/deprecation/您可能还想查看deprecation
库: https://pypi.org/project/deprecation/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.