2 Stimmen

Python-Funktionen können neue Attribute von außerhalb des Anwendungsbereichs erhalten?

Ich wusste nicht, dass man so etwas tun kann:

def tom():
    print "tom's locals: ", locals()

def dick(z):
    print "z.__name__ = ", z.__name__
    z.guest = "Harry"
    print "z.guest = ", z.guest
    print "dick's locals: ", locals()

tom()              #>>> tom's locals:  {}
#print tom.guest    #AttributeError: 'function' object has no attribute 'guest'
print "tom's dir:", dir(tom)  # no 'guest' entry

dick( tom)         #>>> z.__name__ =  tom
                   #>>> z.guest =  Harry
                   #>>> dick's locals:  {'z': <function tom at 0x02819F30>}
tom()              #>>> tom's locals:  {}
#print dick.guest  #AttributeError: 'function' object has no attribute 'guest'

print tom.guest    #>>> Harry
print "tom's dir:", dir(tom)  # 'guest' entry appears

Die Funktion tom() hat keine Locals. Die Funktion dick() weiß, wo tom() wohnt, und legt Harry als 'Gast' bei tom() an. harry erscheint nicht als Local bei tom(), aber wenn Sie nach Toms Gast fragen, antwortet harry. harry ist ein neues Attribut bei tom().

UPDATE: Von außerhalb von tom() können Sie "print dir(tom)" sagen und das Wörterbuch des tom-Objekts sehen. (Man kann das auch von innerhalb tom(), too. So konnte Tom herausfinden, dass er einen neuen Untermieter hatte, Harry, der unter dem Namen "Gast" auftrat).

Attribute können also von außerhalb der Funktion zum Namensraum einer Funktion hinzugefügt werden? Wird das oft gemacht? Ist das eine akzeptable Praxis? Ist es in manchen Situationen empfehlenswert? Ist es manchmal sogar unerlässlich? (Ist es pythonisch?)

UPDATE: Im Titel steht jetzt "Attribute"; früher hieß es "Variablen". Hier ist ein PEP über Funktionsattribute .

4voto

Greg Hewgill Punkte 882617

Ich glaube, Sie verwechseln die Konzepte von lokale Variablen y Funktionsattribute . Weitere Informationen zu Python-Funktionsattributen finden Sie in der SO-Frage Python-Funktionsattribute - Verwendung und Missbrauch .

4voto

Alex Martelli Punkte 805329

@behindthefall, die Motivation, Funktionsobjekten generische zuweisbare Attribute zu geben (früher hatten sie keine), war, dass ohne solche Möglichkeiten reale und populäre Frameworks die wenigen zuweisbaren Attribute missbrauchen würden existierte (typischerweise __doc__ ), um Informationen über jedes gegebene Funktionsobjekt aufzuzeichnen. Es gab also eindeutig eine "aufgestaute Nachfrage" nach dieser Funktionalität, so dass Guido beschloss, sie direkt anzugehen (indem er eine optionale Diktat zu jedem Funktionsobjekt, um seine Attribute aufzuzeichnen, ist keine große Sache - die meisten Funktionsobjekte brauchen es nicht, und es es optional, so dass die Kosten nur 4 Bytes für einen Null-Zeiger betragen;-).

Die Zuweisung solcher Attribute an beliebigen Stellen wäre eine sehr schlechte Praxis, die den Code ohne wirklichen Nutzen schwerer verständlich macht, aber sie sind sehr nützlich, wenn sie auf kontrollierte Weise verwendet werden -- zum Beispiel könnte ein Dekorator sinnvollerweise alle möglichen Dinge über die Funktion, die dekoriert wird, und den Kontext, in dem die Dekoration auftrat, als Attribute der Wrapper-Funktion aufzeichnen, was eine trivial-einfache Introspektion solcher Metadaten zu einem späteren Zeitpunkt, je nach Bedarf, ermöglicht.

Wie bereits in anderen Antworten erwähnt, sind lokale Variablen (die pro Instanz, nicht pro Funktionsobjekt sind!) ein völlig getrennter Namensraum von den Attributen eines Funktionsobjekts, die in dessen __dict__ .

3voto

Smashery Punkte 53538

In Python ist ein Namespace einfach ein Wörterbuchobjekt, das den Variablennamen als String (in diesem Fall "guest") auf einen Wert (in diesem Fall "Harry") abbildet. Solange Sie also Zugriff auf ein Objekt haben und es veränderbar ist, können Sie alles über seinen Namespace ändern.

Bei kleinen Projekten ist das kein großes Problem und ermöglicht eine schnellere Bearbeitung, aber bei größeren Projekten, bei denen die Daten von überall aus geändert werden können, ist das sehr verwirrend.

Es gibt Möglichkeiten, die Attribute von Klassen "privater" zu gestalten, z. B. Namensmanipulation .

1voto

Knio Punkte 5935

Tom.guest ist nur eine Eigenschaft des tom-Funktionsobjekts, sie hat nichts mit dem Anwendungsbereich oder locals() innerhalb dieser Funktion zu tun, und auch nichts mit der Tatsache, dass tom eine Funktion ist, sie würde bei jedem Objekt funktionieren.

1voto

steveha Punkte 70950

Ich habe dies in der Vergangenheit verwendet, um eine in sich geschlossene Funktion mit "Enums" zu erstellen, die mit ihr einhergehen.

Angenommen, ich würde eine seek() Funktion. Die in Python eingebaute Funktion (für Datei-Objekte) benötigt eine ganze Zahl, um zu sagen, wie sie arbeiten soll.

def seek(f, offset, whence=0):
    return f.seek(offset, whence)

seek.START = 0
seek.RELATIVE = 1
seek.END = 2

f = open(filename)

seek(f, 0, seek.START)  # seek to start of file
seek(f, 0, seek.END)  # seek to end of file

Was denken Sie, zu kompliziert und seltsam? Mir gefällt, wie die "enum"-Werte mit der Funktion gebündelt werden; wenn Sie die Funktion aus einem Modul importieren, erhalten Sie automatisch auch die "enum"-Werte.

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