ags*_*ala 154 python annotations function python-3.x
功能注释:PEP-3107
我跑过一段代码,展示了Python3的功能注释.这个概念很简单,但我想不出为什么这些在Python3中实现或者对它们有任何好用.也许SO可以启发我吗?
这个怎么运作:
def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
... function body ...
Run Code Online (Sandbox Code Playgroud)
参数后面后面的所有内容都是"注释",后面的信息->
是函数返回值的注释.
foo.func_annotations将返回一个字典:
{'a': 'x',
'b': 11,
'c': list,
'return': 9}
Run Code Online (Sandbox Code Playgroud)
有这个有什么意义?
Uri*_*Uri 89
我认为这实际上很棒.
来自学术背景,我可以告诉你,注释已证明对于为Java等语言启用智能静态分析器非常有价值.例如,您可以定义语义,如状态限制,允许访问的线程,体系结构限制等,并且有很多工具可以读取这些并处理它们以提供超出编译器的保证.你甚至可以编写检查前置条件/后置条件的东西.
我认为在Python中特别需要这样的东西,因为它的键入较弱,但实际上没有任何构造使得这个简单明了并且是官方语法的一部分.
除了保证之外,注释还有其他用途.我可以看到如何将基于Java的工具应用于Python.例如,我有一个工具,可以让你为方法分配特殊警告,并在你调用它们时给你指示你应该阅读他们的文档(例如,假设你有一个不能用负值调用的方法,但它是名字不直观).通过注释,我可以为Python编写类似的东西.类似地,如果存在官方语法,则可以编写基于标记在大类中组织方法的工具.
Ray*_*ger 87
函数注释就是你对它们的看法.
它们可用于文档:
def kinetic_energy(mass: 'in kilograms', velocity: 'in meters per second'):
...
Run Code Online (Sandbox Code Playgroud)
它们可用于前置条件检查:
def validate(func, locals):
for var, test in func.__annotations__.items():
value = locals[var]
msg = 'Var: {0}\tValue: {1}\tTest: {2.__name__}'.format(var, value, test)
assert test(value), msg
def is_int(x):
return isinstance(x, int)
def between(lo, hi):
def _between(x):
return lo <= x <= hi
return _between
def f(x: between(3, 10), y: is_int):
validate(f, locals())
print(x, y)
>>> f(0, 31.1)
Traceback (most recent call last):
...
AssertionError: Var: y Value: 31.1 Test: is_int
Run Code Online (Sandbox Code Playgroud)
另请参阅http://www.python.org/dev/peps/pep-0362/以获取实现类型检查的方法.
Dus*_*att 41
这是一个迟到的答案,但AFAICT,功能注释目前最好的用途是PEP-0484和MyPy.
Mypy是Python的可选静态类型检查器.您可以使用即将推出的Python 3.5 beta 1(PEP 484)中引入的类型注释标准向Python程序添加类型提示,并使用mypy进行静态类型检查.
像这样使用:
from typing import Iterator
def fib(n: int) -> Iterator[int]:
a, b = 0, 1
while a < n:
yield a
a, b = b, a + b
Run Code Online (Sandbox Code Playgroud)
Muh*_*uri 23
我想补充从我的回答很好地利用的一个具体的例子在这里,加上装饰可以做的多方法的简单机制.
# This is in the 'mm' module
registry = {}
import inspect
class MultiMethod(object):
def __init__(self, name):
self.name = name
self.typemap = {}
def __call__(self, *args):
types = tuple(arg.__class__ for arg in args) # a generator expression!
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(*args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
self.typemap[types] = function
def multimethod(function):
name = function.__name__
mm = registry.get(name)
if mm is None:
mm = registry[name] = MultiMethod(name)
spec = inspect.getfullargspec(function)
types = tuple(spec.annotations[x] for x in spec.args)
mm.register(types, function)
return mm
Run Code Online (Sandbox Code Playgroud)
和使用的一个例子:
from mm import multimethod
@multimethod
def foo(a: int):
return "an int"
@multimethod
def foo(a: int, b: str):
return "an int and a string"
if __name__ == '__main__':
print("foo(1,'a') = {}".format(foo(1,'a')))
print("foo(7) = {}".format(foo(7)))
Run Code Online (Sandbox Code Playgroud)
这可以通过将类型添加到装饰器来完成,如Guido的原始帖子所示,但是注释参数本身更好,因为它避免了参数和类型的错误匹配的可能性.
注:在Python中,你可以访问注解function.__annotations__
,而不是function.func_annotations
因为func_*
风格是关于Python 3去除.
JAB*_*JAB 20
Uri已经给出了正确的答案,所以这里不太严肃:所以你可以缩短你的文档.
wea*_*ver 13
我第一次看到注释,我觉得"很棒!最后我可以选择进行某种类型的检查!" 当然,我没有注意到注释实际上并没有被强制执行.
所以我决定编写一个简单的函数装饰器来强制执行它们:
def ensure_annotations(f):
from functools import wraps
from inspect import getcallargs
@wraps(f)
def wrapper(*args, **kwargs):
for arg, val in getcallargs(f, *args, **kwargs).items():
if arg in f.__annotations__:
templ = f.__annotations__[arg]
msg = "Argument {arg} to {f} does not match annotation type {t}"
Check(val).is_a(templ).or_raise(EnsureError, msg.format(arg=arg, f=f, t=templ))
return_val = f(*args, **kwargs)
if 'return' in f.__annotations__:
templ = f.__annotations__['return']
msg = "Return value of {f} does not match annotation type {t}"
Check(return_val).is_a(templ).or_raise(EnsureError, msg.format(f=f, t=templ))
return return_val
return wrapper
@ensure_annotations
def f(x: int, y: float) -> float:
return x+y
print(f(1, y=2.2))
>>> 3.2
print(f(1, y=2))
>>> ensure.EnsureError: Argument y to <function f at 0x109b7c710> does not match annotation type <class 'float'>
Run Code Online (Sandbox Code Playgroud)
我将它添加到Ensure库中.