5

函数注释似乎复制了 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)?

4

3 回答 3

6

您链接到的 PEP 3107 似乎在其“基本原理”部分中为您的问题提供了答案:

基本原理

由于 Python 的 2.x 系列缺乏注释函数参数和返回值的标准方法,因此出现了各种工具和库来填补这一空白。一些使用“PEP 318”中引入的装饰器,而另一些则解析函数的文档字符串,在那里寻找注释。

此 PEP 旨在提供一种单一的、标准的方式来指定此信息,从而减少由迄今为止存在的机制和语法的广泛变化引起的混淆。

于 2012-08-30T18:53:31.443 回答
6

装饰器语法的意义何在?它不允许你做任何你以前不能做的事情:

@staticmethod
def foo():
    pass

只是

def foo():
    pass
foo = staticmethod(foo)

但是装饰器语法更好。

在这两个中,哪个更好:

@param(a='eggs')
@return_('ni!')
def spam(a):
    pass

def spam(a: 'eggs') -> 'ni!':
    pass

意见可能不同,但我认为第二个更好。

于 2012-08-30T18:54:17.363 回答
0

我非常喜欢类型注释,因为它们可以被我的 IDE PyCharm 识别。通过注释类型,PyCharm 将在我编码时知道变量的类型。这使我可以在一个我可能不完全记住名称的类中找到所需的函数,并在不实际查看该类的代码/文档的情况下查找它们。

正如您所说,与注释不同,类型注释可以从代码中访问。这是一笔巨大的交易,因为它允许创建确保类型的类并根据成员指定的类型提供其他功能。

于 2018-07-11T19:23:51.667 回答