Python build in `unittest.TestCase.assertEquals` 字段的目的是什么

What is purpose of Python build in `unittest.TestCase.assertEquals` field

使用 Python 3.6,PyCharm 社区 2017.2.4,Win 10
我可以搜索,所以我知道 unittest.TestCase.assertEquals() 是已弃用的方法,没关系。
我很好奇的是第一个 field 当我开始输入 assert part for unittest.TestCase.assert[=25 时在 PyCharm IDE =] 首先在代码完成列表中我看到字段 unittest.TestCase.assertEquals。嗯
Ctrl+Q 显示文档

Class attribute assertEquals of class TestCase External documentation: http://docs.python.org/3.6/library/unittest.html#unittest.case.assertEquals

好的 - link 进入关于 unittest 框架的主页
让我们打印值:

Python 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)] on win32
>>> import unittest
>>> unittest.TestCase.assertEquals
<function TestCase._deprecate.<locals>.deprecated_func at 0x03DAC348>
>>> help(unittest.TestCase.assertEquals)
Help on function deprecated_func in module unittest.case:
deprecated_func(*args, **kwargs)

所以这个字段是对被描述的函数的引用 - 我理解的对吗?

这里有一个简短的例子,说明函数修饰在 Python 中是如何工作的。让我们有一个函数,returns 生命、宇宙和一切的终极问题的答案:

def get_answer():
   return 42

如果您检查 get_answer 符号,您会发现它是一个函数:

>>> get_answer
<function get_answer at 0x7f9c4f8bac08>
>>> get_answer()
42

现在让我们决定,返回一个硬编码的答案在其他宇宙中并不真正科学或不可重用,并且该函数应该根据宇宙的实际参数实际计算它。因此引入了一个新函数 compute_answer 并弃用了 get_answer 以支持新函数。要警告用户弃用,可以做几件事:

可以修改源代码以发出警告:

def get_answer():
   print("WARNING: Function get_answer is deprecated")
   return 42

这很难看,因为它引入了函数源代码的更改。更好的方法是包装函数:

def deprecated(func):
   def show_deprecated():
      print("WARNING: Function {} is deprecated".format(func.__name__))
      return func()
   return show_deprecated

这里发生的是我们将一个函数传递给 deprecated 函数,后者构建并 returns 一个包装器。包装器是嵌套 show_deprecated 函数的一个实例,它在调用时捕获(记住)func 参数的值。这称为 闭包,是函数式编程的基石之一。

我们现在可以通过 deprecated 将调用路由到 get_answer 以获得自动弃用消息,而无需更改函数源代码中的任何内容:

>>> get_answer_dep = deprecated(get_answer)
>>> get_answer_dep()
WARNING: Function get_answer is deprecated
42

我们还可以用它的包装版本覆盖 get_answer,以便所有对它的调用都通过包装器路由:

>>> get_answer = deprecated(get_answer)
>>> get_answer()
WARNING: Function get_answer is deprecated
42

此时无法再访问 get_answer 的原始非包装代码。它仍然存在并被包装器函数调用,但是没有公开可见的符号允许我们直接调用它(仍然可以通过包装器的内省调用原始代码,但让我们假装我们不知道怎么做)。如果您现在检查 get_answer 符号,它实际上是 show_deprecated 函数的一个实例:

>>> get_answer
<function show_deprecated at 0x7f9c4218b140>

由于help(something)显示的是对象本身的__doc__属性,调用help(get_answer)实际上显示的是show_deprecated的doc-string:

>>> help(get_answer)
Help on function show_deprecated in module __main__:
show_deprecated()

在每个弃用函数之后写 name = deprecated(name) 有点乏味。这就是 Python 提供快捷语法的原因:

@deprecated
def get_answer()
   return 42

@deprecated语法被称为函数修饰。它只是指示解释器在函数定义之后插入对装饰器函数的调用,在本例中为 deprecated(),并将结果分配给带有函数名称的符号,即:

@foo
def bar():
   ...

相当于:

def bar():
   ...

bar = foo(bar)

unittest 模块没有使用 source code.

中的装饰器语法

help() 显示了包装函数的帮助,而不是原来的帮助,这在调试时很糟糕。幸运的是,函数名称和文档字符串实际上是可写属性,可以将它们从原始函数复制到包装器中,从而保留 help() 显示的名称和文档字符串。 Python 附带了 functools 模块,该模块提供了 wraps 装饰器,正是这样做的。装饰器用于嵌套(包装)函数:

from functools import wraps

def deprecated(func):
   @wraps(func)
   def show_deprecated():
      print("WARNING: Function {} is deprecated".format(func.__name__))
      return func()
   return show_deprecated

如果我们现在包装 get_answer 函数,名称、文档和模块属性将被保留:

 >>> get_answer = deprecated(get_answer)
 >>> help(get_answer)
 Help on function get_answer in module __main__:
 get_answer()