2013-01-17 22 views
175

Python 3.3 grammar specificationを見たとき、私は最近、面白いことを気づいた:Pythonの関数定義で - >はどういう意味ですか?

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

オプションの「矢印」ブロックは、Python 2には存在しなかったと私は、Python 3でその意味に関するあらゆる情報を見つけることができなかったことが判明これが正しいのPythonで、それはインタプリタで受け入れています:

def f(x) -> 123: 
    return x 

私はこれが前提条件構文のいくつかの種類かもしれないと思ったが、:

  • ここではxはテストできませんが、まだ未定義です。
  • 矢印の後ろに何を置いても問題ありません。 2 < 1)、関数の動作には影響しません。

この構文に慣れている人は誰でも説明できますか?

答えて

137

これはfunction annotationです。

より詳しくは、Python 2.xにはドキュメントストリングがあり、さまざまなタイプのオブジェクトにメタデータストリングを添付することができます。これは驚くほど便利なので、Python 3は、パラメータと戻り値を記述する関数にメタデータを添付することで、この機能を拡張しています。

予期される使用例はありませんが、PEPではいくつか提案しています。非常に便利なのは、パラメータに期待される型で注釈を付けることです。注釈を検証するデコレータを書くことや、引数を正しい型に強制するデコレータを書くのは簡単でしょう。もう一つは、ドキュメンテーション文字列にエンコーディングするのではなく、パラメータ固有のドキュメンテーションを可能にすることです。

+46

この情報は '.__ annotations__'属性として利用できます。 –

+1

うわー、私は知識の広範な領域を欠場しました。値の注釈だけでなく、パラメータ注釈も返します。どうもありがとうございました :)。 – Krotton

+1

@Krottonそれを見逃したことにあなたを責めることはできませんが、実際には使用されていません。私はそれらを使って1つのライブラリにしか会ったことがなく、それはかなりわかりません。 – delnan

85

これらは、PEP 3107で扱われる機能注釈です。具体的には、->はreturn関数アノテーションをマークします。

例:

>>> '{:,} {}'.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 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'} 

、あなたはこれを行うことができますので、

または、関数属性を使用して呼び出された値を検証することができます。

他の回答として
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) 

プリント

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

->シンボルが機能アノテーションの一部として使用され、述べました。しかし最近のPython >= 3.5のバージョンでは、があり、と定義されています。

PEP 3107 -- Function Annotationsは、文法の変更を定義する仕様を記述しており、それらが格納されているfunc.__annotations__の存在と、そのユースケースがまだ開いているという事実が記述されています。

しかし、3.5では、PEP 484 -- Type Hintsはこれに単一の意味を付けます。->は、関数が返す型を示すために使用されます。また、What about existing uses of annotationsで説明したように、これは将来のバージョンに適用されますように思える:

最速考えられるスキームは3.6で非型ヒント注釈のサイレント廃止、3.7で完全な廃止、および宣言型のヒントをご紹介しますPython 3.8でアノテーションの唯一の許可された使用法として使用されています。

(重点鉱山)

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

例は、あなたが与えてきた。これによると、:

def f(x) -> int: 
    return x 

def f(x) -> 123: 
    return x 

は、将来的に禁止されます(現在のバージョンでは混乱を招くことになる)、それはに変更する必要があるだろうが

その機能を効果的に記述するためにfは、タイプintのオブジェクトを返します。

注釈はPython自体では決して使用されません。注釈はほとんど人口を集めて無視します。それらを扱うのは第三者図書館の責任です。

関連する問題