Ist es möglich, dass eine Liste in Python auf faule Weise ausgewertet wird?
Zum Beispiel
a = 1
list = [a]
print list
#[1]
a = 2
print list
#[1]
Wenn die Liste faul ausgewertet wäre, würde die letzte Zeile [2] sein
Ist es möglich, dass eine Liste in Python auf faule Weise ausgewertet wird?
Zum Beispiel
a = 1
list = [a]
print list
#[1]
a = 2
print list
#[1]
Wenn die Liste faul ausgewertet wäre, würde die letzte Zeile [2] sein
Das Konzept der "faulen" Auswertung kommt normalerweise in funktionalen Sprachen vor - aber in denen könnte man nicht zwei verschiedene Werte derselben Bezeichnung neu zuweisen, daher könnte auch dort Ihr Beispiel nicht reproduziert werden.
Es geht überhaupt nicht um Faulheit - vielmehr ist es garantiert, dass die Verwendung einer Bezeichnung identisch damit ist, eine Referenz auf denselben Wert zu erhalten, auf den diese Bezeichnung verweist, und eine Bezeichnung neu zuzuweisen, also einem nackten Namen, um einen anderen Wert zu machen, garantiert, dass die Bezeichnung ab diesem Zeitpunkt auf einen anderen Wert verweist. Die Referenz auf den ersten Wert (Objekt) geht nicht verloren.
Betrachten Sie ein ähnliches Beispiel, bei dem keine Neuzuweisung an einen nackten Namen stattfindet, sondern jede andere Art von Mutation (für ein veränderliches Objekt, natürlich - Zahlen und Strings sind unveränderlich), einschließlich einer Zuweisung an etwas anderes als einen nackten Namen:
>>> a = [1]
>>> liste = [a]
>>> print liste
[[1]]
>>> a[:] = [2]
>>> print liste
[[2]]
Da es kein a - ...
gibt, das den nackten Namen a
neu zuweist, sondern ein a[:] = ...
, das den Inhalt von a
neu zuweist, ist es trivial, Python so "faul" zu machen, wie Sie möchten (und tatsächlich wäre es sogar etwas Aufwand, es "gierig" zu machen!;-)... wenn Faulheit gegenüber Gier in einem dieser Fälle eine Rolle spielen würde (was nicht der Fall ist;-).
Seien Sie sich einfach der vollkommen einfachen Semantik des "Zuweisens an einen nackten Namen" bewusst (im Gegensatz zum Zuweisen an irgendetwas anderes, was durch Verwendung Ihrer eigenen Typen entsprechend angepasst und gesteuert werden kann), und die optische Illusion von "faul vs eifrig" wird hoffentlich verschwinden;-)
Bin auf diesen Beitrag gestoßen, als ich nach einer echten Implementierung einer faulen Liste gesucht habe, aber es klang wie etwas Lustiges, was man ausprobieren könnte.
Die folgende Implementierung macht grundsätzlich das, was ursprünglich gefragt wurde:
from collections import Sequence
class LazyClosureSequence(Sequence):
def __init__(self, get_items):
self._get_items = get_items
def __getitem__(self, i):
return self._get_items()[i]
def __len__(self):
return len(self._get_items())
def __repr__(self):
return repr(self._get_items())
Man verwendet es so:
>>> a = 1
>>> l = LazyClosureSequence(lambda: [a])
>>> print l
[1]
>>> a = 2
>>> print l
[2]
Das ist offensichtlich schrecklich.
Python ist im Allgemeinen nicht wirklich sehr faul.
Sie können Generatoren verwenden, um träge Datenstrukturen zu emulieren (wie unendliche Listen usw.), aber was die Verwendung von normaler Listen-Syntax betrifft, usw., werden Sie keine Trägheit haben.
Dies ist eine schreibgeschützte Lazy-Liste, für die nur eine vordefinierte Länge und eine Cache-Update-Funktion erforderlich sind:
importieren Sie copy
importieren Sie Operationen
von Sammlungen.abc import Sequenz
von functools import partialmethod
von Eingabe importieren Dict, Union
def _cmp_list(a: list, b: list, op, if_eq: bool, if_long_a: bool) -> bool:
"""Hilfsfunktion zum Implementieren der Klassenoperatoren gt|ge|lt|le"""
wenn a ist b:
zurück, wenn_eq
for ia, ib in zip(a, b):
wenn ia == ib:
fortfahren
zurück op(ia, ib)
la, lb = len(a), len(b)
wenn la == lb:
zurück, wenn_eq
wenn la > lb:
zurück, wenn_long_a
zurück nicht, wenn_long_a
Klasse LazyListView(Sequenz):
def __init__(self, Länge):
self._range = Bereich(Länge)
self._cache: Dict[int, Wert] = {}
def __len__(self) -> int:
zurück len(self._range)
def __getitem__(self, ix: Union[int, slice]) -> Wert:
Länge = len(self)
wenn isinstance(ix, slice):
klon = copy.copy(self)
klon._range = self._range[slice(*ix.indices(length))] # schneiden
zurück klon
sonst:
wenn ix < 0:
ix += len(self) # negative Indizes zählen vom Ende
wenn nicht (0 <= ix < Länge):
raise IndexError(f"Listeindex {ix} außerhalb des Bereichs [0, {length})")
wenn ix nicht in self._cache:
... # Cache aktualisieren
zurück self._cache[ix]
def __iter__(self) -> dict:
für i, _row_ix in enumerate(self._range):
yield self[i]
__eq__ = _eq_list
__gt__ = partialmethod(_cmp_list, op=operator.gt, if_eq=False, if_long_a=True)
__ge__ = partialmethod(_cmp_list, op=operator.ge, if_eq=True, if_long_a=True)
__le__ = partialmethod(_cmp_list, op=operator.le, if_eq=True, if_long_a=False)
__lt__ = partialmethod(_cmp_list, op=operator.lt, if_eq=False, if_long_a=False)
def __add__(self, other):
"""BRICHT die LALISZITÄT und gibt eine einfache Liste zurück"""
return list(self) + other
def __mul__(self, Faktor):
"""BRICHT die LALISZITÄT und gibt eine einfache Liste zurück"""
return list(self) * Faktor
__radd__ = __add__
__rmul__ = __mul__
Beachten Sie, dass diese Klasse auch in diesem SO diskutiert wird.
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.