Skip to main content
 首页 » 编程设计

python 文档测试和协程

2025年05月04日16xing901022

我在使用 doctest 和协程时遇到了一些麻烦...

def coroutine(func): 
    def start(*args, **kwargs): 
        cr=func(*args, **kwargs) 
        cr.next() 
        return cr 
    start.__name__=func.__name__ 
    return start 
 
@coroutine 
def leader_tracking(): 
    """ 
    Tracks 'leader' status - only returns transitions 
 
    >>> lt=leader_tracking() 
    >>> print lt.send(False) 
 
    >>> print lt.send(False) 
 
    """ 
    last_status=False 
    result=("nop", None) 
 
    while True: 
        status=(yield result) 
 
        if status!=last_status: 
            direction="up" if last_status==False else "down" 
            last_status=status 
            result=("tr", direction) 
        else: 
            result=("nop", None) 

如果我使用通常的 doctest 脚手架:

if __name__=="__main__": 
    import doctest 
    doctest.testmod() 

doctest 不显示任何内容,而如果我使用更强力的方法:

lt=leader_tracking() 
print lt.send(True) 
print lt.send(False) 
print lt.send(False) 
print lt.send(True) 
print lt.send(True) 
print lt.send(True) 
print lt.send(True) 
print lt.send(False) 

我可以看到预期的结果:

('tr', 'up') 
('tr', 'down') 
('nop', None) 
('tr', 'up') 
('nop', None) 
('nop', None) 
('nop', None) 
('tr', 'down') 

doctest 我做错了什么?

请您参考如下方法:

doctest 模块查看存储在函数的 __doc__ 属性中的文档字符串。您的协程装饰器仅复制 __name__,因此文档字符串丢失并且 doctest 无法找到它。您可以手动分配 __doc__ 属性,但更好的方法是使用 functools 模块:

import functools 
 
def coroutine(func): 
    @functools.wraps(func) 
    def start(*args, **kwargs): 
        cr = func(*args, **kwargs) 
        cr.next() 
        return cr 
    return start 

functools.wraps 装饰器将 func 的所有各种元数据属性复制到包装函数 start 中,包括 docstring,以便 doctest将按预期工作。

另请注意,为了正常工作,您的 doctest 注释应包含预期的输出:

@coroutine 
def leader_tracking(): 
    """ 
    Tracks 'leader' status - only returns transitions 
 
    >>> lt=leader_tracking() 
    >>> print lt.send(True) 
    ('tr', 'up') 
    >>> print lt.send(False) 
    ('tr', 'down') 
    >>> print lt.send(False) 
    ('nop', None) 
    """ 
    last_status = False 
    result = ("nop", None) 
 
    while True: 
        status = yield result 
 
        if status != last_status: 
            direction = "up" if last_status == False else "down" 
            last_status = status 
            result = ("tr", direction) 
        else: 
            result = ("nop", None)