当前位置: 首页 > 知识库问答 >
问题:

为什么函数注释需要Python中的专用语法?

勾裕
2023-03-14

函数注释似乎重复了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的,其中

@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)时,为什么没有关于如何使用注释的强制定义?

共有3个答案

宰父学
2023-03-14

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

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

堵彬彬
2023-03-14

decorator语法的意义是什么?它不允许你做以前做不到的事情:

@staticmethod
def foo():
    pass

只是

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

但是decorator语法更好。

在这两者中,哪一个更好:

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

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

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

闽念
2023-03-14

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

根本原因

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

这个PEP旨在提供一种单一的、标准的方法来指定这些信息,减少由于机制和语法的广泛变化而造成的混乱。

 类似资料:
  • 我读了这篇问答和Cocoacasts博文,我完全理解什么是< code>@escaping注释。 但老实说,我不明白我们为什么需要它。 上述Cocoacasts博客文章指出: 默认情况下,使闭包不转义有几个好处。最明显的好处是性能和编译器优化代码的能力。如果编译器知道闭包是非转义的,它可以处理内存管理的许多细节。 但是,Swift编译器可以确定<code>转义 这也意味着您可以在非转义闭包中使用s

  • 一个更一般的问题。如果在常规Spring托管类中使用构造函数注入,则这些类将自动连接,而不需要@autowired注释,即: 在@SpringBootTest类中遵循相同的构造函数注入原则,您需要将@Autowired注释设置为构造函数参数,否则它将无法注入该类,即: 为什么会出现这种差异?

  • 我刚刚发现了Python3的函数注释(https://www.python.org/dev/peps/pep-3107/)这对于记录参数或返回类型似乎很有用。它还可以在我的pycharm IDE中提供更好的intellisense。 我有一个关于输入类型模糊的参数的问题。例如,它可以是一个列表或numpy数组或一些“类似数组”的数量。为函数注释此类输入参数的最佳方法是什么?例子: 我还有一个例子,

  • 问题内容: 我从节点启动这是来自node.js README.md 先决条件(仅Unix): 想知道为什么node.js需要Python?它是否在其API下使用Python 问题答案: Node.js使用GYP构建-GYP —用Python编写的跨平台构建工具。Python中还实现了其他一些构建步骤。因此,从源代码构建节点需要Python。 但是您还需要Python来构建本机插件。

  • 问题内容: 我对此代码有疑问:https : //github.com/reactjs/redux/blob/master/examples/async/containers/App.js 特别: 我猜这是一个两部分的问题。 为什么我需要将句柄更改设置为类的实例,我不能只对handleChange使用静态函数并直接在类中调用它 ? 我不知道这是怎么回事: 谢谢 问题答案: 以相反的顺序回答… 返回

  • 本文向大家介绍使用箭头函数应该需要注意什么?相关面试题,主要包含被问及使用箭头函数应该需要注意什么?时的应答技巧和注意事项,需要的朋友参考一下