Frage

Betrachten Sie diese Code :

a = {...} # a is an dict with arbitrary contents
b = a.copy()
  1. Welche Rolle spielt die Veränderlichkeit Spiel in den Schlüsseln und Werten der dicts?
  2. Wie stelle ich sicher Änderungen an Schlüssel oder Werte eines dict sind nicht in den anderen reflektiert?
  3. Wie verhält sich dies auf die hashable Einschränkung der dict Schlüssel?
  4. Gibt es Unterschiede im Verhalten zwischen Python 2.x und Python 3.x?

Wie kann ich überprüfen, ob ein Typ in Python wandelbar ist?

War es hilfreich?

Lösung

1) Die Schlüssel müssen nicht wandelbar sein, es sei denn, Sie haben eine benutzerdefinierte Klasse, die hashable aber auch wandelbar ist. Das ist alles, was auf euch gezwungen wird. jedoch mit einem hashable, veränderbares Objekt als dict Schlüssel könnte eine schlechte Idee sein.

2) von nicht-Wert zwischen den beiden dicts teilen. Es ist OK, um die Schlüssel zu teilen, weil sie unveränderlich sein muss. Kopieren Sie das Wörterbuch, in dem copy Modul Sinn, ist auf jeden Fall sicher. Der Aufruf der dict Konstruktor hier funktioniert auch: b = dict(a). Sie könnten auch unveränderliche Werte verwenden.

3) Alle eingebauten in unveränderlichen Typen hashable sind. Alle eingebauten in änderbare Typen sind nicht hashable. Für ein Objekt hashable zu sein, muss es den gleichen Hash über die gesamte Lebensdauer, auch wenn es mutiert ist.

4) Nicht, dass mir bewusst; Ich beschreibe 2.x.

Ein Typ ist wandelbar, wenn es nicht unveränderlich ist. Ein Typ ist unveränderlich, wenn es einen eingebauten in unveränderlichen Typ ist: str, int, long, bool, float, tuple, und wahrscheinlich ein paar andere, die ich vergessen habe. Benutzerdefinierte Typen sind immer wandelbar.

Ein Objekt ist wandelbar, wenn es nicht unveränderlich ist. Ein Objekt ist unveränderlich, wenn sie besteht, rekursiv, nur unveränderlich typisierte Unterobjekte. Somit ist ein Tupel von Listen wandelbar; Sie können die Elemente des Tupels ersetzen, aber man kann sich durch die Liste Schnittstelle ändern, die Gesamtdaten zu ändern.

Andere Tipps

Es gibt nicht wirklich so etwas wie Veränderlichkeit oder Unveränderlichkeit auf der Sprachebene in Python. Einige Objekte bieten keine Möglichkeit, sie zu ändern (zB Strings und Tupel.), Und so sind effektiv unveränderlich, aber es ist rein begrifflich; es gibt kein Eigentum an dem Sprachniveau angibt, das weder auf Ihren Code noch zu Python selbst.

Unveränderlichkeit ist nicht wirklich relevant dicts; es ist völlig in Ordnung, veränderbare Werte als Schlüssel zu verwenden. Was zählt, ist der Vergleich und Hashing: das Objekt immer sich selbst gleich bleiben muss. Zum Beispiel:

class example(object):
    def __init__(self, a):
        self.value = a
    def __eq__(self, rhs):
        return self.value == rhs.value
    def __hash__(self):
        return hash(self.value)

a = example(1)
d = {a: "first"}
a.data = 2
print d[example(1)]

Hier example ist nicht unveränderlich; wir modifizieren es mit a.data = 2. Und doch sind wir es als Schlüssel eines Hash ohne Probleme verwenden. Warum? Die Immobilie Wir ändern hat keine Auswirkungen auf die Gleichstellung. Der Hash ist unverändert, und example(1) ist immer gleich example(1), alle anderen Eigenschaften zu ignorieren

Die häufigste Verwendung dieser ist Caching und memoization. Mit einer Eigenschaft im Cache oder nicht logisch das Objekt nicht ändern, und hat in der Regel keinen Einfluss auf Gleichheit

(Ich werde hier stoppen -. Bitte fragen Sie nicht fünf Fragen auf einmal)

Es gibt MutableSequence, MutableSet, MutableMapping in Modul Sammlungen . Die verwendet werden können Veränderlichkeit von vorgefertigten Typen zu überprüfen.

issubclass(TYPE, (MutableSequence, MutableSet, MutableMapping))

Wenn Sie dies wollen, verwenden Sie auf benutzerdefinierte Typen, muss der Typ entweder von einem von ihnen oder registriert als virtuelle Unterklasse vererbt werden.

class x(MutableSequence):
    ...

oder

class x:
    ...

abc.ABCMeta.register(MutableSequence,x)

Es gibt wirklich keine Garantie , dass ein Typ, den hashable ist auch unveränderlich ist, aber bei dest richtig __hash__ Implementierung erfordert, dass der Typ unveränderlich ist, in Bezug auf seine eigene Hash und auf Gleichheit. Dies ist nicht in einer bestimmten Art und Weise durchgesetzt werden.

Wir sind aber alle Erwachsenen. Es wäre unklug, __hash__ zu implementieren, wenn Sie wirklich gemeint. Grob gesagt, dies läuft darauf hinaus, nur um zu sagen, dass, wenn ein Typ kann tatsächlich als Wörterbuch Schlüssel verwendet werden, dann ist es beabsichtigt, in dieser Weise verwendet werden.

Wenn Sie nach etwas suchen, das ist wie ein dict, sondern auch unveränderlich, dann

  1. dict Tasten muss hashable sein, was bedeutet, sie haben einen unveränderlichen Hash Wert. dict Werte können oder nicht sein wandelbar; aber wenn sie wandelbar diese Auswirkungen auf Ihre zweite Frage.

  2. „Änderungen an den Tasten“ wird nicht zwischen den beiden dicts widerspiegeln. Änderungen an unveränderliche Werte, wie Strings werden auch nicht berücksichtigt werden. Änderungen an veränderliche Objekte, wie benutzerdefinierte Klassen werden reflektiert werden, da das Objekt durch ID (das heißt Referenz) gespeichert ist.

    class T(object):
      def __init__(self, v):
        self.v = v
    
    
    t1 = T(5)
    
    
    d1 = {'a': t1}
    d2 = d1.copy()
    
    
    d2['a'].v = 7
    d1['a'].v   # = 7
    
    
    d2['a'] = T(2)
    d2['a'].v   # = 2
    d1['a'].v   # = 7
    
    
    import copy
    d3 = copy.deepcopy(d2) # perform a "deep copy"
    d3['a'].v = 12
    d3['a'].v   # = 12
    d2['a'].v   # = 2
    
  3. Ich denke, das durch die ersten beiden Antworten erklärt.

  4. Nicht, dass ich von in dieser Hinsicht kennen.

einige zusätzliche Gedanken :

Es gibt zwei wichtigsten Dinge für das Verständnis des Verhaltens von wissen, Tasten : Tasten müssen a href sein <= „http://docs.python.org/glossary.html#term-hashable“ rel = "nofollow"> hashable (das heißt, sie implementieren object.__hash__(self) ), und sie müssen auch „vergleichbar“ sein (das heißt, sie so etwas wie object.__cmp__(self) ). Ein wichtiges Mitnehmen von dem docs: standardmäßig benutzerdefinierte Objekte Hash-Funktionen geben id() .

Betrachten Sie dieses Beispiel:

class K(object):
  def __init__(self, x, y):
     self.x = x
     self.y = y
  def __hash__(self):
     return self.x + self.y

k1 = K(1, 2)
d1 = {k1: 3}
d1[k1] # outputs 3
k1.x = 5
d1[k1] # KeyError!  The key's hash has changed!
k2 = K(2, 1)
d1[k2] # KeyError!  The key's hash is right, but the keys aren't equal.
k1.x = 1
d1[k1] # outputs 3

class NewK(object):
  def __init__(self, x, y):
     self.x = x
     self.y = y
  def __hash__(self):
     return self.x + self.y
  def __cmp__(self, other):
     return self.x - other.x

nk1 = NewK(3, 4)
nd1 = {nk1: 5}
nd1[nk1] # outputs 5
nk2 = NewK(3, 7)
nk1 == nk2 # True!
nd1[nk2] # KeyError! The keys' hashes differ.
hash(nk1) == hash(nk2) # False
nk2.y = 4
nd1[nk2] # outputs 5

# Where this can cause issues:
nd1.keys()[0].x = 5
nd1[nk1] # KeyError! nk1 is no longer in the dict!
id(nd1.keys()[0]) == id(nk1)  # Yikes. True?!
nd1.keys()[0].x = 3
nd1[nk1]  # outputs 5
id(nd1.keys()[0]) == id(nk1)  # True!

Werte sind viel einfacher zu verstehen, die dict speichert Verweise auf Objekte. Lesen Sie die Abschnitte auf hashable. Dinge wie Strings sind unveränderlich, wenn Sie „ändern“ sie, die dict Sie es in jetzt ein neues Objekt verweist geändert. Objekte, die wandelbar sind, können „geändert in-place“ werden, damit der Wert beider dicts wird sich ändern.

d1 = {1: 'a'}
d2 = d1.copy()
id(d1[1]) == id(d2[1]) # True
d2[1] = 'z'
id(d1[1]) == id(d2[1]) # False

# the examples in section 2 above have more examples of this.

Wie auch immer, hier sind die wichtigsten Punkte aller dieser:

  • für Tasten , kann es nicht sein Veränderlichkeit , sondern hashability und Vergleichbarkeit , dass Sie kümmern sich um.
  • Sie sorgen für Werte über Veränderlichkeit, weil per definitionem ein veränderbares Objekt Wert kann ohne Änderung der Verweis auf sie geändert werden.

Ich glaube nicht, gibt es eine allgemeine Möglichkeit zu testen, eine dieser beiden Punkte. Die Tests zur Eignung würden auf Ihrem Anwendungsfall abhängen. Zum Beispiel kann es ausreichend zu prüfen sein, dass ein Objekt tut oder nicht __hash__ und Vergleich (__eq__ oder __cmp__) Funktionen implementieren. Like-wiese, könnten Sie in der Lage sein, „Kontrolle“ ein __setattr__ Methode des Objekts in irgendeiner Art und Weise zu bestimmen, ob es wandelbar ist.

Dicts sind ungeordnete Sätze von Schlüssel: Wert-Paaren. Die Tasten müssen unveränderlich, und daher hashable. Um zu bestimmen, ob ein Objekt hashable ist, können Sie die hash()-Funktion:

>>> hash(1)
1
>>> hash('a')
12416037344
>>> hash([1,2,3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash((1,2,3))
2528502973977326415
>>> hash({1: 1})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Die Werte, auf der anderen Seite kann jedes Objekt sein. Wenn Sie prüfen müssen, ob ein Objekt unveränderlich ist, dann würde ich hash() verwenden.

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