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 .

0voto

fengb Punkte 1428

Python-Funktionen sind lexikalisch skaliert, so dass es keine Möglichkeit gibt, der Funktion Variablen außerhalb ihres definierten Bereichs hinzuzufügen.

Allerdings hat die Funktion immer noch Zugriff auf alle übergeordneten Bereiche, wenn Sie das System wirklich so gestalten wollen (was allerdings allgemein als schlechte Praxis gilt):

>>> def foo():
>>>     def bar():
>>>         print x
>>>     x = 1
>>>     bar()
1

Das Mutieren von Funktionsvariablen ist meist eine schlechte Idee, da Funktionen als unveränderlich gelten. Die pythonischste Art, dieses Verhalten zu implementieren, ist stattdessen die Verwendung von Klassen und Methoden.

0voto

elo80ka Punkte 13417

Werkzeuge zur Erstellung von Python-API-Dokumentation, wie z. B. pydoc y epydoc verwenden Sie die Introspektion, um den Namen und den Docstring einer Funktion zu ermitteln (verfügbar als __name__ y __doc__ Attribute). Von braven Funktionsdekoratoren wird erwartet, dass sie diese Attribute erhalten, so dass solche Werkzeuge weiterhin wie erwartet funktionieren (d.h. das Dekorieren einer Funktion sollte die Dokumentation der dekorierten Funktion erhalten). Sie tun dies, indem Sie diese Attribute von der dekorierten Funktion zum Dekorator kopieren. Werfen Sie einen Blick auf update_wrapper im functools Modul:

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
WRAPPER_UPDATES = ('__dict__',)

def update_wrapper(wrapper,
                   wrapped,
                   assigned = WRAPPER_ASSIGNMENTS,
                   updated = WRAPPER_UPDATES):
    """Update a wrapper function to look like the wrapped function

       wrapper is the function to be updated
       wrapped is the original function
       ...
    """
    for attr in assigned:
        setattr(wrapper, attr, getattr(wrapped, attr))
    for attr in updated:
        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
    ...

Das ist also zumindest ein Beispiel dafür, dass die Änderung von Funktionsattributen nützlich und akzeptiert ist.

In manchen Situationen kann es nützlich sein, eine Funktion durch Setzen eines Attributs zu "kommentieren"; Django verwendet dies an einigen Stellen:

  • Sie können einstellen alters_data auf Wahr bei Modellmethoden, die die Datenbank ändern, und verhindern so, dass sie in Vorlagen aufgerufen werden.

  • Sie können einstellen allow_tags über Modellmethoden, die in der Verwaltung angezeigt werden, um bedeutet, dass die Methode einen HTML Inhalt zurückgibt, der nicht automatisch escaped werden sollte.

Wie immer sollten Sie Ihr Urteilsvermögen einsetzen. Wenn das Ändern von Attributen akzeptierte Praxis ist (z.B. beim Schreiben eines Dekorators), dann machen Sie auf jeden Fall weiter. Wenn es Teil einer gut dokumentiert API, ist das wahrscheinlich auch in Ordnung.

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