函数注释似乎复制了 Python 中已经发现的行为。不仅如此,它们的含义并未以任何方式强制执行,因此它们可用于PEP 3107中记录的以下任何内容:
- 提供打字信息
- 类型检查
- 让 IDE 显示函数期望和返回的类型
- 函数重载/泛型函数
- 外语桥梁
- 适应
- 谓词逻辑函数
- 数据库查询映射
- RPC 参数封送
- 其他信息
- 参数和返回值的文档
甚至是完全不同的东西。
在某种程度上,函数注释让我想起了Python 幽默合集中的一个老笑话:
事实上,Python 已经支持块分隔符:
> > if foo: #{ > foo1(); > foo2(); > foo3(); > #}
在那里面
def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
...
没有比以下更有帮助的:
# a: 'x', b: 5 + 6, c: list
def foo(a, b, c): #-> max(2, 9):
...
有人可能会争辩说函数注释是必要的,因为与注释不同,它们可以从代码中访问,例如:
>>> def spam(a: 'eggs') -> 'ni!':
... pass
...
>>> spam.__annotations__
{'a': 'eggs', 'return': 'ni!'}
尽管可以使用装饰器轻松实现相同的行为,例如:
def param(**kw):
def decorator(func):
def wrap(*args):
print kw
func(*args)
return wrap
return decorator
def return_(arg):
def decorator(func):
def wrap(*args):
func(*args)
print arg
return wrap
return decorator
@param(a='eggs')
@return_('ni!')
def spam(a):
pass
spam(None)
# Output:
# -------
## {'a': 'eggs'}
## ni!
Python 已经可以做注解的事情了,那为什么函数注解需要专门的语法呢?
编辑:我将对我的问题进行一些扩展,因为它的含义变得有点不清楚。
我专门问这个问题是关于函数注释而不是装饰器,其中
@decorator
def spam():
pass
简称
def spam():
pass
spam = decorator(spam)
和方法调用,其中
self.method(param)
简称
Class.method(self, param)
有了这两个速记句法快捷方式,它们的含义就不会改变。我不是在问为什么在已有替代方案的情况下需要这样的捷径;这是一个可读性问题。函数注释与这两个快捷方式略有不同,因为
def spam() -> int:
pass
和
def spam() -> 'integer':
pass
可能与人类具有相同的含义,但与计算机具有不同的含义。即使程序员知道注释应该定义什么,也没有就注释如何定义它达成一致的定义。此外,注释不会影响功能,因此不需要保持一致。
所以这是我修改后的问题:
当函数注释提供了一种可变且可能不一致的方式来访问已经存在的语言特性时,为什么它们需要专门的语法?为什么没有关于如何使用注释的强制定义,而对于它们的用途有一个完美的定义( PEP 3107)?