Frage

Wie genau funktioniert die Python auswerten Attribute der Klasse?Ich habe stolperte über eine interessante Eigenart (in Python 2.5.2), dass ich gern erklärt.

Ich habe eine Klasse mit einigen Parametern definiert werden in Bezug auf andere, zuvor den vorgegebenen Parametern.Wenn ich versuche über ein generator-Objekt, Python wirft einen Fehler, aber wenn ich eine Ebene gewöhnlicher Liste Verständnis, es ist kein problem.

Hier ist die abgespeckte Beispiel.Beachten Sie, dass der einzige Unterschied ist, dass Brie verwendet einen generator, der Ausdruck, während Cheddar benutzt eine list comprehension.

# Using a generator expression as the argument to list() fails
>>> class Brie :
...     base = 2
...     powers = list(base**i for i in xrange(5))
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in Brie
  File "<stdin>", line 3, in <genexpr>
NameError: global name 'base' is not defined

# Using a list comprehension works
>>> class Cheddar :
...     base = 2
...     powers = [base**i for i in xrange(5)]
... 
>>> Cheddar.powers
[1, 2, 4, 8, 16]

# Using a list comprehension as the argument to list() works
>>> class Edam :
...     base = 2
...     powers = list([base**i for i in xrange(5)])
...
>>> Edam.powers
[1, 2, 4, 8, 16]

(Meine eigentliche Fall war komplizierter, und ich habe ein dict, aber dies ist das minimale Beispiel, das ich finden konnte.)

Meine einzige Vermutung ist, dass die Liste Verstehens sind berechnet auf die Linie, aber der generator-Ausdrücke berechnet werden, die nach dem Ende der Klasse, an welchem Punkt der Umfang geändert hat.Aber ich bin mir nicht sicher, warum der generator-Ausdruck kann nicht als eine Schließung und speichern den Verweis auf Basis im Umfang an die Linie.

Gibt es einen Grund für diese, und wenn ja, wie sollte ich denken, die Bewertung mechanik der Attribute der Klasse?

War es hilfreich?

Lösung

Ja, es ist ein bisschen vertrackt, diese.Eine Klasse ist nicht wirklich vorstellen, einen neuen Rahmen, es einfach irgendwie sieht ein bisschen so aus wie es tut;Konstrukte wie das aussetzen der Unterschied.

Die Idee ist, dass, wenn Sie einen generator-Ausdruck ist äquivalent zu tun es mit einem lambda:

class Brie(object):
    base= 2
    powers= map(lambda i: base**i, xrange(5))

oder explizit als eine Funktion-Anweisung:

class Brie(object):
    base= 2

    def __generatePowers():
        for i in xrange(5):
            yield base**i

    powers= list(__generatePowers())

In diesem Fall ist es klar, dass base nicht im Bereich für __generatePowers;eine Ausnahme ergibt für beide (es sei denn, Sie waren unglücklich genug zu haben auch ein base global, in diesem Fall erhalten Sie eine Falschheit).

Dies geschieht nicht für die Liste Verstehens durch einige interne details, wie man Sie bewertet, aber dieses Verhalten geht Weg, in Python 3, das wird scheitern gleichermaßen für beide Fälle. Einige Diskussionen hier.

Eine Problemumgehung kann mit einem lambda-Ausdruck mit der gleichen Technik setzten wir auf zurück in den schlechten alten Tagen, bevor nested_scopes:

class Brie(object):
    base= 2
    powers= map(lambda i, base= base: base**i, xrange(5))

Andere Tipps

Von PEP 289:

Nach der Erkundung der vielen Möglichkeiten, eine Konsens, dass die verbindlichen Themen waren schwer zu verstehen, und Benutzern sollten nachdrücklich aufgefordert, generator-Ausdrücke in Funktionen konsumieren Sie Ihre Argumente sofort.Für komplexere Anwendungen, die vollständige-generator Definitionen sind immer in superior hinsichtlich der offensichtlich über Umfang, Leben und Bindung [6].

[6] (1, 2) - Patch Diskussion und alternative Flecken auf Source Forge http://www.python.org/sf/872326

Es ist, wie generator-Ausdrücke beschränkt, soweit ich kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top