922 Stimmen

Was bedeutet -> in Python-Funktionsdefinitionen?

Kürzlich habe ich etwas Interessantes bemerkt, als ich mir Python 3.3 Grammatik-Spezifikation :

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

Der optionale "arrow"-Block fehlte in Python 2, und ich konnte keine Informationen über seine Bedeutung in Python 3 finden. Es stellte sich heraus, dass dies korrektes Python ist und vom Interpreter akzeptiert wird:

def f(x) -> 123:
    return x

Ich dachte, dass dies eine Art Vorbedingungssyntax sein könnte, aber:

  • Ich kann nicht testen x da sie noch nicht definiert ist,
  • Egal, was ich nach dem Pfeil einfüge (z. B. 2 < 1 ), hat dies keine Auswirkungen auf das Verhalten der Funktion.

Könnte jemand, der mit diesem Syntaxstil vertraut ist, ihn erklären?

682voto

Katriel Punkte 115208

Es ist ein Funktionskommentar .

In Python 2.x gibt es docstrings, die es Ihnen ermöglichen, eine Metadaten-Zeichenkette an verschiedene Objekttypen anzuhängen. Das ist erstaunlich praktisch, und Python 3 erweitert diese Funktion, indem es Ihnen erlaubt, Metadaten an Funktionen anzuhängen, die ihre Parameter und Rückgabewerte beschreiben.

Es gibt keinen vorgefertigten Anwendungsfall, aber das PEP schlägt mehrere vor. Ein sehr praktischer Fall ist es, es zu erlauben, Parameter mit ihren erwarteten Typen zu annotieren; es wäre dann einfach, einen Dekorator zu schreiben, der die Annotationen verifiziert oder die Argumente zum richtigen Typ zwingt. Eine andere ist es, parameter-spezifische Dokumentation zu erlauben, anstatt sie in den docstring zu kodieren.

592voto

dawg Punkte 89931

Dies sind Funktionskommentare, die in PEP 3107 . Genauer gesagt, die -> markiert den Vermerk der Rückgabefunktion.

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 sind Wörterbücher, so dass Sie dies tun können:

>>> '{:,} {}'.format(kinetic_energy(12,30),
      kinetic_energy.__annotations__['return'])
'5,400.0 Joules'

Sie können auch eine Python-Datenstruktur statt nur einer Zeichenkette verwenden:

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 aufgerufene Werte zu validieren:

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>

296voto

MaxiMouse Punkte 3505

Im folgenden Code:

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

die -> int sagt nur, dass f() gibt eine ganze Zahl zurück (erzwingt aber nicht, dass die Funktion eine ganze Zahl zurückgibt). Sie wird als return annotation und kann aufgerufen werden als f.__annotations__['return'] .

Python unterstützt auch Parameter-Annotationen:

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

: float sagt Leuten, die das Programm (und einige Bibliotheken/Programme von Dritten, z. B. pylint) lesen, dass x sollte ein float . Sie wird aufgerufen als f.__annotations__['x'] und hat für sich genommen keine Bedeutung. Siehe die Dokumentation für weitere Informationen:

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

130voto

Wie bereits in anderen Antworten erwähnt, ist die -> Symbol wird als Teil von Funktionsanmerkungen verwendet. In neueren Versionen von Python >= 3.5 Allerdings hat es einen definiert Bedeutung.

PEP 3107 -- Funktionsanmerkungen die Beschreibung der Spezifikation, die Definition der Grammatikänderungen, das Vorhandensein von func.__annotations__ in dem sie gespeichert sind, und die Tatsache, dass der Anwendungsfall noch offen ist.

In Python 3.5 Allerdings, PEP 484 -- Hinweise zum Typ eine einzige Bedeutung beimisst: -> wird verwendet, um den Typ anzugeben, den die Funktion zurückgibt. Es sieht auch so aus, als ob dies in zukünftigen Versionen erzwungen werden wird, wie beschrieben in Was ist mit den bestehenden Verwendungsmöglichkeiten von Kommentaren? :

Das schnellste denkbare Schema würde die stille Verwerfung von Nicht-Typ-Hinweis-Annotationen in 3.6, die vollständige Verwerfung in 3.7 und Typ-Hinweise als die einzige erlaubte Verwendung von Anmerkungen in Python 3.8 zu deklarieren.

(Hervorhebung von mir)

Dies wurde bisher noch nicht umgesetzt. 3.6 Soweit ich das beurteilen kann, könnte es also in zukünftige Versionen verschoben werden.

Demnach ist das von Ihnen angeführte Beispiel:

def f(x) -> 123:
    return x

in Zukunft verboten sein wird (und in den aktuellen Versionen verwirrend sein wird), müsste es geändert werden in:

def f(x) -> int:
    return x

um diese Funktion effektiv zu beschreiben f gibt ein Objekt vom Typ int .

Die Anmerkungen werden von Python selbst in keiner Weise verwendet, es füllt sie so gut wie aus und ignoriert sie. Es ist bis zu 3rd-Party-Bibliotheken, mit ihnen zu arbeiten.

14voto

Vitalii Punkte 169

Dies bedeutet die Art des Ergebnisses, das die Funktion zurückgibt, aber es kann sein None .

Sie ist in modernen, an Python 3.x orientierten Bibliotheken weit verbreitet.

Zum Beispiel gibt es im Code der Bibliothek pandas-profiling zum Beispiel an vielen Orten:

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.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X