我正在Github(linkhttps://github.com/goodfeli/adversarial/blob/master/deconv.py)中阅读Ian Goodfellow的GAN源代码。特别是在第40/41行,代码为:
@functools.wraps(Model.get_lr_scalers)
def get_lr_scalers(self):
这是一种相当陌生的使用wraps
的方法,似乎目标是用用户定义的函数替换get_lr_scalers
。但是那样的话,我们就不需要包装了,对吧?我真的不知道在这种情况下wraps
的目的。你知道吗
^{} 默认情况下,将另一个函数的许多属性复制到此函数上,
__module__
、__name__
、__qualname__
、__annotations__
和__doc__
。你知道吗最明显有用的复制方法是
__doc__
。考虑这个简单的例子:1现在如果有人想使用
help(mychild.spam)
,他们会得到29行有用的信息。(或者,如果他们在PyCharm中自动完成mychild.spam
,它会弹出文档的覆盖图,等等)所有这些都不需要我手动复制和粘贴。而且,更好的是,如果Base
来自某个我没有编写的框架,并且我的用户从该框架的1.2.3升级到1.2.4,并且有一个更好的docstring,他们会看到更好的docstring。你知道吗在最常见的情况下,
Child
将是Base
的一个子类,spam
将是一个重写。2但这实际上不是必需的-wraps
并不关心您是通过继承进行子类型化,还是通过实现隐式协议进行duck类型化;这两种情况都同样有用。只要Child
打算实现来自Base
的spam
协议,那么Child.spam
具有相同的docstring(可能还有其他元数据属性)是有意义的。你知道吗其他属性可能没有docstring那么有用。例如,如果您使用的是类型注释,那么它们在读取代码方面的优势可能至少与能够运行Mypy进行静态类型检查方面的优势一样高,因此仅从另一个方法动态复制它们通常并不那么有用。和
__module__
和__qualname__
主要用于反射/检查,在这种情况下更可能是误导而不是帮助(尽管您可能会提出一个框架示例,希望人们阅读Base
中的代码,而不是Child
中的代码,但对于默认的明显示例,这不是正确的)。但是,除非它们是有害的,否则使用@functools.wraps(Base.spam, assigned=('__doc__',))
而不是默认值的可读性成本可能不值得。你知道吗1。如果您使用的是python2,请将这些类更改为从
object
继承;否则它们将是旧式的类,这只会以一种不相关的方式使事情复杂化。如果是Python3,则没有旧式类,因此甚至不会出现此问题。2。或者可能是ABC的“虚拟子类”,通过
register
调用或子类挂钩声明。@wraps
的目的是将一个函数的元信息复制到另一个函数。这通常是在通过包装替换原始函数时完成的,这通常是由装饰器完成的。你知道吗但在一般情况下,下面是一个例子:
现在,您可以测试发生了什么:
当您调用
f2
时,很明显它实际上是f2
,但是当您检查它时,它的行为就像f1
——它有相同的文档字符串和相同的名称。你知道吗那有什么用?为此:
现在,原来的f1被一个新功能所取代,但从外观上看它仍然像
f1
。你知道吗通常是在装修工那里完成的:
它的行为是这样的:
相关问题 更多 >
编程相关推荐