->在Python函数定义中是什么意思?

问题:->在Python函数定义中是什么意思?

我最近在查看Python 3.3语法规范时发现了一些有趣的东西:

funcdef: 'def' NAME parameters ['->' test] ':' suite

Python 2中没有可选的“箭头”块,我在Python 3中找不到有关其含义的任何信息。事实证明这是正确的Python,并且已被解释器接受:

def f(x) -> 123:
    return x

我认为这可能是某种前提语法,但是:

  • 我无法x在此处进行测试,因为它仍未定义,
  • 无论我在箭头后面加什么(例如2 < 1),它都不会影响功能行为。

习惯此语法的任何人都可以解释吗?

I’ve recently noticed something interesting when looking at Python 3.3 grammar specification:

funcdef: 'def' NAME parameters ['->' test] ':' suite

The optional ‘arrow’ block was absent in Python 2 and I couldn’t find any information regarding its meaning in Python 3. It turns out this is correct Python and it’s accepted by the interpreter:

def f(x) -> 123:
    return x

I thought that this might be some kind of a precondition syntax, but:

  • I cannot test x here, at it is still undefined,
  • No matter what I put after the arrow (e.g. 2 < 1), it doesn’t affect the function behaviour.

Could anyone accustomed with this syntax explain it?


回答 0

这是一个功能注释

更详细地讲,Python 2.x具有文档字符串,可用于将元数据字符串附加到各种类型的对象。这非常方便,因此Python 3通过允许您将元数据附加到描述其参数和返回值的函数来扩展了该功能。

没有预想的用例,但是PEP建议了几个。一种非常方便的方法是允许您使用期望的类型注释参数。这样就很容易编写一个装饰器来验证注释或将参数强制为正确的类型。另一个是允许特定于参数的文档,而不是将其编码为文档字符串。

It’s a function annotation.

In more detail, Python 2.x has docstrings, which allow you to attach a metadata string to various types of object. This is amazingly handy, so Python 3 extends the feature by allowing you to attach metadata to functions describing their parameters and return values.

There’s no preconceived use case, but the PEP suggests several. One very handy one is to allow you to annotate parameters with their expected types; it would then be easy to write a decorator that verifies the annotations or coerces the arguments to the right type. Another is to allow parameter-specific documentation instead of encoding it into the docstring.


回答 1

这些是PEP 3107中涵盖的功能注释。具体来说,->标记是返回函数注释。

例子:

>>> def kinetic_energy(m:'in KG', v:'in M/S')->'Joules': 
...    return 1/2*m*v**2
... 
>>> kinetic_energy.__annotations__
{'return': 'Joules', 'v': 'in M/S', 'm': 'in KG'}

注释是字典,因此您可以执行以下操作:

>>> '{:,} {}'.format(kinetic_energy(20,3000),
      kinetic_energy.__annotations__['return'])
'90,000,000.0 Joules'

您还可以拥有一个python数据结构,而不仅仅是一个字符串:

>>> rd={'type':float,'units':'Joules','docstring':'Given mass and velocity returns kinetic energy in Joules'}
>>> def f()->rd:
...    pass
>>> f.__annotations__['return']['type']
<class 'float'>
>>> f.__annotations__['return']['units']
'Joules'
>>> f.__annotations__['return']['docstring']
'Given mass and velocity returns kinetic energy in Joules'

或者,您可以使用函数属性来验证调用的值:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        try: 
            pr=test.__name__+': '+test.__docstring__
        except AttributeError:
            pr=test.__name__   
        msg = '{}=={}; Test: {}'.format(var, value, pr)
        assert test(value), msg

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    _between.__docstring__='must be between {} and {}'.format(lo,hi)       
    return _between

def f(x: between(3,10), y:lambda _y: isinstance(_y,int)):
    validate(f, locals())
    print(x,y)

版画

>>> f(2,2) 
AssertionError: x==2; Test: _between: must be between 3 and 10
>>> f(3,2.1)
AssertionError: y==2.1; Test: <lambda>

These are function annotations covered in PEP 3107. Specifically, the -> marks the return function annotation.

Examples:

>>> def kinetic_energy(m:'in KG', v:'in M/S')->'Joules': 
...    return 1/2*m*v**2
... 
>>> kinetic_energy.__annotations__
{'return': 'Joules', 'v': 'in M/S', 'm': 'in KG'}

Annotations are dictionaries, so you can do this:

>>> '{:,} {}'.format(kinetic_energy(20,3000),
      kinetic_energy.__annotations__['return'])
'90,000,000.0 Joules'

You can also have a python data structure rather than just a string:

>>> rd={'type':float,'units':'Joules','docstring':'Given mass and velocity returns kinetic energy in Joules'}
>>> def f()->rd:
...    pass
>>> f.__annotations__['return']['type']
<class 'float'>
>>> f.__annotations__['return']['units']
'Joules'
>>> f.__annotations__['return']['docstring']
'Given mass and velocity returns kinetic energy in Joules'

Or, you can use function attributes to validate called values:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        try: 
            pr=test.__name__+': '+test.__docstring__
        except AttributeError:
            pr=test.__name__   
        msg = '{}=={}; Test: {}'.format(var, value, pr)
        assert test(value), msg

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    _between.__docstring__='must be between {} and {}'.format(lo,hi)       
    return _between

def f(x: between(3,10), y:lambda _y: isinstance(_y,int)):
    validate(f, locals())
    print(x,y)

Prints

>>> f(2,2) 
AssertionError: x==2; Test: _between: must be between 3 and 10
>>> f(3,2.1)
AssertionError: y==2.1; Test: <lambda>

回答 2

如其他答案所述,该->符号用作功能注释的一部分。>= 3.5但是,在最新版本的Python中,它具有定义的含义。

PEP 3107-功能注释描述了规范,定义了语法更改,func.__annotations__它们存储在其中的存在以及用例的事实仍然是开放的。

但是在Python中3.5PEP 484-类型提示对此具有唯一含义:->用于指示函数返回的类型。看起来这将在将来的版本中强制执行,如注释的现有用法如何

最快的可能方案将在3.6中引入对非类型提示注释的静默弃用,在3.7中引入完全弃用,并将类型提示声明为Python 3.8中唯一允许使用的注释。

(强调我的)

3.6据我所知,实际上尚未真正实现,因此可能会与将来的版本发生冲突。

据此,您提供了示例:

def f(x) -> 123:
    return x

将来会被禁止(并且在当前版本中会令人困惑),因此需要将其更改为:

def f(x) -> int:
    return x

为了有效地描述该函数f返回一个类型的对象int

Python本身不以任何方式使用这些注释,它几乎填充并忽略了它们。与他们合作的取决于第三方图书馆。

As other answers have stated, the -> symbol is used as part of function annotations. In more recent versions of Python >= 3.5, though, it has a defined meaning.

PEP 3107 — Function Annotations described the specification, defining the grammar changes, the existence of func.__annotations__ in which they are stored and, the fact that it’s use case is still open.

In Python 3.5 though, PEP 484 — Type Hints attaches a single meaning to this: -> is used to indicate the type that the function returns. It also seems like this will be enforced in future versions as described in What about existing uses of annotations:

The fastest conceivable scheme would introduce silent deprecation of non-type-hint annotations in 3.6, full deprecation in 3.7, and declare type hints as the only allowed use of annotations in Python 3.8.

(Emphasis mine)

This hasn’t been actually implemented as of 3.6 as far as I can tell so it might get bumped to future versions.

According to this, the example you’ve supplied:

def f(x) -> 123:
    return x

will be forbidden in the future (and in current versions will be confusing), it would need to be changed to:

def f(x) -> int:
    return x

for it to effectively describe that function f returns an object of type int.

The annotations are not used in any way by Python itself, it pretty much populates and ignores them. It’s up to 3rd party libraries to work with them.


回答 3

在下面的代码中:

def f(x) -> int:
    return int(x)

-> int刚刚告诉f()返回一个整数(但并不强制函数返回一个整数)。它称为返回注释,可以通过进行访问f.__annotations__['return']

Python还支持参数注释:

def f(x: float) -> int:
    return int(x)

: float告诉阅读该程序(和某些第三方库/程序,例如pylint)的人员x应为float。它以形式访问f.__annotations__['x'],其本身没有任何意义。请参阅文档以获取更多信息:

https://docs.python.org/3/reference/compound_stmts.html#function-definitions https://www.python.org/dev/peps/pep-3107/

In the following code:

def f(x) -> int:
    return int(x)

the -> int just tells that f() returns an integer (but it doesn’t force the function to return an integer). It is called a return annotation, and can be accessed as f.__annotations__['return'].

Python also supports parameter annotations:

def f(x: float) -> int:
    return int(x)

: float tells people who read the program (and some third-party libraries/programs, e. g. pylint) that x should be a float. It is accessed as f.__annotations__['x'], and doesn’t have any meaning by itself. See the documentation for more information:

https://docs.python.org/3/reference/compound_stmts.html#function-definitions https://www.python.org/dev/peps/pep-3107/


回答 4

这意味着函数返回的结果类型,但可以是None

它在面向Python 3.x的现代库中很普遍。

例如,在很多地方,库pandas-profiling中都有代码,例如:

def get_description(self) -> dict:

def get_rejected_variables(self, threshold: float = 0.9) -> list:

def to_file(self, output_file: Path or str, silent: bool = True) -> None:
"""Write the report to a file.

This means the type of result the function returns, but it can be None.

It is widespread in modern libraries oriented on Python 3.x.

For example, it there is in code of library pandas-profiling in many places for example:

def get_description(self) -> dict:

def get_rejected_variables(self, threshold: float = 0.9) -> list:

def to_file(self, output_file: Path or str, silent: bool = True) -> None:
"""Write the report to a file.

回答 5

def function(arg)->123:

它只是一个返回类型,在这种情况下,整数与您写入的数字无关紧要。

Java一样:

public int function(int args){...}

但是对于Python(Jim Fasarakis Hilliard怎么说) ,返回类型只是一个提示,因此建议返回,但是无论如何都允许返回其他类型,例如字符串。

def function(arg)->123:

It’s simply a return type, integer in this case doesn’t matter which number you write.

like Java :

public int function(int args){...}

But for Python (how Jim Fasarakis Hilliard said) the return type it’s just an hint, so it’s suggest the return but allow anyway to return other type like a string..


回答 6

def f(x) -> 123:
    return x

我的总结:

  1. 简单->介绍它是为了使开发人员可以选择指定函数的返回类型。请参阅Python增强建议3107

  2. 这表明随着Python的广泛采用,事情将来会如何发展-这是强类型化的迹象-这是我个人的观察。

  3. 您也可以为参数指定类型。指定函数和参数的返回类型将有助于减少逻辑错误并改进代码增强功能。

  4. 您可以将表达式作为返回类型(对于函数和参数级别),并且可以通过注释对象的’return’属性访问表达式的结果。对于lambda内联函数的表达式/返回值,注释将为空。

def f(x) -> 123:
    return x

My summary:

  1. Simply -> is introduced to get developers to optionally specify the return type of the function. See Python Enhancement Proposal 3107

  2. This is an indication of how things may develop in future as Python is adopted extensively – an indication towards strong typing – this is my personal observation.

  3. You can specify types for arguments as well. Specifying return type of the functions and arguments will help in reducing logical errors and improving code enhancements.

  4. You can have expressions as return type (for both at function and parameter level) and the result of the expressions can be accessed via annotations object’s ‘return’ attribute. annotations will be empty for the expression/return value for lambda inline functions.