web-dev-qa-db-ja.com

Pythonの関数定義で - >はどういう意味ですか?

最近見たときにおもしろいことに気付いた Python 3.3文法仕様

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

Python 2にはオプションの 'arrow'ブロックはありませんでしたが、Python 3ではその意味に関する情報を見つけることができませんでした。

def f(x) -> 123:
    return x

私はこれがある種の前提条件構文であるかもしれないと思いました、しかし:

  • ここでxをテストすることはできません。未定義のままです。
  • 矢印の後に何を置いても(たとえば2 < 1)、関数の動作には影響しません。

この構文に慣れた人なら誰でもそれを説明できますか?

314
Krotton

それは 関数アノテーション です。

より詳細には、Python 2.xにはdocstringがあり、これを使ってメタデータ文字列をさまざまなタイプのオブジェクトに添付することができます。これは驚くほど便利です。Python3では、パラメータと戻り値を記述する関数にメタデータを添付できるようにすることで、機能を拡張しています。

先入観のあるユースケースはありませんが、PEPはいくつか提案しています。非常に便利なのは、パラメータに予想される型で注釈を付けることができるようにすることです。その場合、注釈を検証したり、引数を正しい型に強制したりするデコレータを書くのは簡単でしょう。もう1つは、docstringにエンコードするのではなく、パラメータ固有のドキュメントを許可することです。

248
Katriel

これらは 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.__  
        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>
166
dawg

他の答えが述べているように、->シンボルは関数アノテーションの一部として使われています。最近のバージョンのPython >= 3.5では、 defined の意味があります。

PEP 3107 - 関数アノテーション 仕様を記述し、文法の変更、それらが格納されているfunc.__annotations__の存在、それがまだユースケースであるという事実を定義します。

しかしPythonでは3.5PEP 484 - Type Hints はこれに一つの意味を付けます:->は関数が返す型を示すために使われます。これは、 注釈の既存の使用法について で説明されているように、将来のバージョンでも適用されるように思われます。

考えられる最速のスキームでは、3.6では非型ヒント注釈のサイレント非推奨、3.7では完全型非推奨、および Python 3.8での注釈の唯一の許可された使用法として型ヒントを宣言します。

(私の強調)

私が言うことができる限り、これは実際には3.6の時点で実装されていないので、将来のバージョンにぶつかるかもしれません。

これによると、あなたが提供した例:

def f(x) -> 123:
    return x

将来禁止されるでしょう(そして現在のバージョンでは混乱するでしょう)、それは次のように変更される必要があるでしょう:

def f(x) -> int:
    return x

その関数fが効果的にその型を表すintのオブジェクトを返すようにするためです。

アノテーションはPython自身では決して使われていません。それはほとんど存在し、それらを無視します。それらを扱うのはサードパーティーのライブラリ次第です。

Pythonはそれを無視します。次のコードでは:

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

-> intf()が整数を返すことを伝えるだけです。これはreturnアノテーションと呼ばれ、f.__annotations__['return']としてアクセスできます。

Pythonはパラメータアノテーションもサポートしています。

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

: floatは、プログラム(およびいくつかのサードパーティのライブラリ/プログラム、たとえばpylint)を読む人に、xfloatであるべきであることを伝えます。これはf.__annotations__['x']としてアクセスされ、それ自体では意味がありません。詳細についてはドキュメントを参照してください。

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

4
MaxiMouse

def function(arg)->123:

これは単に戻り値の型です。integerはどの数値を書いても構いません。

Javaのように:

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

しかし、Pythonの場合(どのように Jim Fasarakis Hilliard と言った)戻り値の型は単なるヒントですとにかく文字列のような他の型を返すために..

0