【发布时间】:2011-03-14 14:21:55
【问题描述】:
谁能给我一些使用 Python 3 中引入的函数注释的 Python 开源项目示例?
我想看看这个功能的一些实际用途,看看我是否可以在我自己的项目中使用它。
【问题讨论】:
标签: python-3.x
谁能给我一些使用 Python 3 中引入的函数注释的 Python 开源项目示例?
我想看看这个功能的一些实际用途,看看我是否可以在我自己的项目中使用它。
【问题讨论】:
标签: python-3.x
我从未见过在野外使用此功能。但是,我在为USENIX ;Login: 撰写的一篇关于 Python 3 的文章中探讨了函数注释的一个潜在用途,即用于执行合同。例如,您可以这样做:
from functools import wraps
def positive(x):
'must be positive'
return x > 0
def negative(x):
'must be negative'
return x < 0
def ensure(func):
'Decorator that enforces contracts on function arguments (if present)'
return_check = func.__annotations__.get('return',None)
arg_checks = [(name,func.__annotations__.get(name))
for name in func.__code__.co_varnames]
@wraps(func)
def assert_call(*args):
for (name,check),value in zip(arg_checks,args):
if check:
assert check(value),"%s %s" % (name, check.__doc__)
result = func(*args)
if return_check:
assert return_check(result),"return %s" % (return_check.__doc__)
return result
return assert_call
# Example use
@ensure
def foo(a:positive, b:negative) -> positive:
return a-b
如果你这样做,你会看到这样的行为:
>>> foo(2,-3)
5
>>> foo(2,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "ensure.py", line 22, in assert_call
assert check(value),"%s %s" % (name, check.__doc__)
AssertionError: b must be negative
我应该注意到,上面的示例需要进一步充实,才能与默认参数、关键字参数和其他细节一起正常工作。这只是一个想法的草图。
现在,这是否是一个好主意,我只是不知道。我倾向于同意 Brandon 的观点,即缺乏可组合性是一个问题——特别是如果注释开始被不同的库用于不同的目的。我还想知道是否不能通过装饰器来完成类似这种合同想法的事情。例如,制作一个像这样使用的装饰器(实现留作练习):
@ensure(a=positive,b=negative)
def foo(a,b):
return a-b
历史记录,我一直觉得函数注释是 Python 社区 10 多年前关于“可选静态类型”讨论的产物。这是否是最初的动机,我只是不知道。
【讨论】:
我会玩脾气暴躁,并建议不要使用该功能。希望有一天它会被删除。到目前为止,Python 在部署有吸引力、正交且可以堆叠的特性方面做得很好——函数装饰器就是一个很好的例子:如果我使用三个不同的库都希望我装饰我的函数,结果看起来相当干净:
@lru_cache(max_items=5)
@require_basic_auth
@view('index.html')
def index(…):
⋮
但是这个新奇的笨拙的“注释”功能将 Python 带到了相反的方向:因为你只能对给定的函数进行一次精确的注释,它完全破坏了从各个部分组合解决方案的能力。如果您有两个库,每个库都希望您代表它们注释相同的函数,那么据我所知,您将完全受阻。
【讨论】: