Behave 的装饰器是如何创建/声明的?
我现在正在使用Behave(Python的行为驱动开发工具),并且一直在研究它的源代码,想弄明白@given
、@when
和@then
这些装饰器是怎么定义的。
我查到的最远的地方是step_registry.py
,在这里我发现了一个函数setup_step_decorators(context=None, registry=registry)
,看起来这个函数就是在做这件事。
不过,我不太明白这些装饰器是怎么创建的,因为在源代码中并没有以def when(...):
这样的形式明确声明。我觉得它们是根据一个字符串列表来定义的(for step_type in ('given', 'when', 'then', 'step'):
),然后通过调用make_decorator()
来处理。
有没有人能帮我看一下代码,解释一下这些装饰器是在哪里以及怎么被声明的?
你可以在这里访问Behave的源代码。
2 个回答
3
它们是在大约第90行被注入到 globals()
中的(那时 context
是 globals()
,因为 context
是 None
):
# -- Create the decorators
def setup_step_decorators(context=None, registry=registry):
if context is None:
context = globals()
for step_type in ('given', 'when', 'then', 'step'):
step_decorator = registry.make_decorator(step_type)
context[step_type.title()] = context[step_type] = step_decorator
你也可以自己这样做(globals()
的工作方式就像一个普通的字典):
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> globals()['a'] = 5
>>> a
5
5
好吧,我们从外面开始讲:
if context is None:
context = globals()
for step_type in ('given', 'when', 'then', 'step'):
step_decorator = registry.make_decorator(step_type)
context[step_type.title()] = context[step_type] = step_decorator
我觉得让你困惑的是最后一行。
每个模块的全局命名空间其实就是一个字典。函数 globals()
会返回这个字典。如果你修改这个字典,就会创建新的模块全局变量。例如:
>>> globals()['a'] = 2
>>> a
2
在这种情况下,默认情况下,context = globals()
。所以,对于第一个 step_type
,你实际上是在做这个:
>>> globals()['given'] = step_decorator