2013-01-17 9 views
175

Ich habe vor kurzem bemerkt, etwas interessant, wenn bei Python 3.3 grammar specification suchen:Was bedeutet -> in Python-Funktionsdefinitionen?

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

Der optionale ‚Pfeil‘ Block war abwesend in Python 2 und ich konnte nicht finden alle Informationen in Bezug auf seine Bedeutung in Python 3. Es stellt sich heraus das ist richtig Python und es wird vom Interpreter akzeptiert:

def f(x) -> 123: 
    return x 

ich dachte, dass dies eine Art Vorbedingung Syntax, aber:

  • kann ich hier x nicht testen, es ist immer noch undefiniert,
  • Egal was ich nach dem Pfeil (z. 2 < 1), hat dies keinen Einfluss auf das Funktionsverhalten.

Könnte jemand mit dieser Syntax vertraut erklären?

Antwort

137

Es ist ein function annotation.

Im Detail, Python 2.x hat Docstrings, mit denen Sie eine Metadaten-String an verschiedene Arten von Objekten anhängen können. Das ist erstaunlich praktisch, daher erweitert Python 3 das Feature, indem es Ihnen ermöglicht, Metadaten an Funktionen anzuhängen, die ihre Parameter und Rückgabewerte beschreiben.

Es gibt keinen vorgefassten Anwendungsfall, aber die PEP schlägt mehrere vor. Eine sehr praktische Möglichkeit ist, dass Sie Parameter mit ihren erwarteten Typen annotieren können; es wäre dann einfach, einen Dekorator zu schreiben, der die Anmerkungen verifiziert oder die Argumente in den richtigen Typ umwandelt. Eine andere Möglichkeit besteht darin, eine parameterspezifische Dokumentation zuzulassen, anstatt sie in den Docstring zu codieren.

+46

Und die Informationen sind als '.__ Annotations__' Attribut verfügbar. –

+1

Wow, ich habe ein ziemlich breites Wissensgebiet vermisst - nicht nur die Rückgabe von Anmerkungen, sondern auch die Annotation von Parametern. Vielen Dank :). – Krotton

+1

@Krotton Kann dir nicht vorwerfen, dass du es vermisst hast, es ist praktisch nicht benutzt. Ich habe nur eine einzige Bibliothek getroffen, die sie benutzt, und es ist ziemlich unklar. – delnan

85

Dies sind Funktionskommentare in PEP 3107. Insbesondere markiert die -> die Annotation der Rückkehrfunktion.

Beispiele:

>>> 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'} 

Anmerkungen Wörterbücher sind, so können Sie dies tun:

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

Sie können auch ein Python-Datenstruktur, anstatt einfach nur einen 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' 

Oder Sie können Funktionsattribute verwenden, um die aufgerufenen Werte zu überprüfen:

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) 

Drucke

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

Wie andere Antworten angegeben haben, wird das -> Symbol als Teil der Funktion Anmerkungen verwendet. In neueren Versionen von Python >= 3.5 hat es jedoch eine definierte Bedeutung.

PEP 3107 -- Function Annotations beschrieben die Spezifikation, definieren die Grammatik Änderungen, die Existenz von func.__annotations__, in denen sie gespeichert sind, und die Tatsache, dass es Anwendungsfall ist noch offen.

In Python 3.5 obwohl, fügt PEP 484 -- Type Hints eine einzige Bedeutung zu diesem: -> wird verwendet, um den Typ anzugeben, der die Funktion zurückgibt. Es scheint auch, wie dies in zukünftigen Versionen erzwungen werden, wie in What about existing uses of annotations beschrieben:

Der schnellste denkbare Schema nicht-Typ-Hinweis Anmerkungen einführen würde in 3.6, voll deprecation in 3,7 und declare Typ Hinweise stille deprecation von als einzige zulässige Verwendung von Anmerkungen in Python 3.8.

(Hervorhebung von mir)

Dies ist eigentlich nicht als von 3.6 so weit umgesetzt, wie ich sagen kann, so könnte es auf zukünftige Versionen gestoßen erhalten.

dies nach, das Beispiel Sie geliefert haben:

def f(x) -> 123: 
    return x 

wird in Zukunft verboten werden (und in aktuellen Versionen verwirrend sein), wäre es zu geändert werden müssen:

def f(x) -> int: 
    return x 

für die effektive Beschreibung dieser Funktion f gibt ein Objekt vom Typ int zurück.

Die Anmerkungen werden in keiner Weise von Python selbst verwendet, es füllt sie ziemlich auf und ignoriert sie. Es liegt an den Bibliotheken von Drittanbietern, mit ihnen zu arbeiten.