经过长时间的咨询,这是我的第一个问题。我已经搜索了很多这个问题,我想我没有找到任何有用的信息来解决它。
我正在尝试为Python 3中的代码创建一个通用的弃用python装饰器。目标是正确地包装一个函数或类做两件事:打印关于弃用的警告,并在__doc__
前面添加弃用信息(也可由sphinx
处理)。我想我已经整理了我想要的大部分内容,我仍然在与Sphinx挣扎,但我发现了对functools.wraps
的行为感到好奇。基本上,包装类的__dict__
类型为dict
,而未展开的类类型为mappingproxy
。
这是一些展示代码:
import functools
class Deprecated(object):
def __call__(self, cls):
myassigns = functools.WRAPPER_ASSIGNMENTS
myassigns += ('__mro__',)
@functools.wraps(cls, assigned=myassigns)
def new_func(*args, **kwargs):
warnings.warn(message, category=DeprecationWarning, stacklevel=2)
return cls(*args, **kwargs)
return new_func
@Deprecated()
class SomeOldClass:
def some_method(self, x, y):
return x + y
class SomeClass:
def some_method(self, x, y):
return x + y
print(type(SomeOldClass.__dict__))
print(type(SomeClass.__dict__))
输出:
<class 'dict'>
<class 'mappingproxy'>
functools.wraps
行为不端还是我做错了什么?
答案 0 :(得分:0)
Extreme care should be exercised when writing code that uses
subgroups if the goal is to write portable OpenCL applications.
不是行为不端也不是你在技术上做错了什么,你已经返回了在被叫时会返回实例的功能。
包装后,functools.wrap
是您包装并返回的函数SomeOldClass
:
new_func
不是班级。未装饰的>>> SomeOldClass
<function __main__.SomeOldClass>
将保留为SomeClass
为__dict__
的类。
答案 1 :(得分:0)
我强烈建议让你的包装类知道,所以它不包装类本身:
class Deprecated(object):
def __init__(self, messagefmt='{wrapped} is deprecated'):
self.messagefmt = messagefmt
def __call__(self, wrapped):
message = self.messagefmt.format(wrapped=wrapped.__name__)
wrappingclass = isinstance(wrapped, type)
if wrappingclass:
wrappedfunc = wrapped.__init__
else:
wrappedfunc = wrapped
@functools.wraps(wrappedfunc)
def new_func(*args, **kwargs):
warnings.warn(message, category=DeprecationWarning, stacklevel=2)
return wrappedfunc(*args, **kwargs)
wrapped.__doc__ = 'Deprecated\n\n' + message + '\n\n' + (wrapped.__doc__ or '')
if wrappingclass:
wrapped.__init__ = new_func
return wrapped
else:
return new_func
这使您可以在两个类中使用它:
@Deprecated()
class SomeOldClass:
def some_method(self, x, y):
return x + y
不会模糊类行为和函数(可能使用自定义弃用消息):
@Deprecated('foo is dead')
def foo():
pass
所以当你使用它们时:
>>> import warnings
>>> warnings.filterwarnings('always', category=DeprecationWarning)
>>> SomeOldClass()
/usr/local/bin/ipython3:1: DeprecationWarning: SomeOldClass is deprecated
#!/usr/bin/python3
<__main__.SomeOldClass at 0x7fea8f744a20>
>>> foo()
/usr/local/bin/ipython3:1: DeprecationWarning: foo is dead
#!/usr/bin/python3
同样地,两者的__doc__
被修改为预先添加弃用通知(您可以将其调整为Sphinxify,我只是提供基本示例)。