Domanda

codice :

a = {...} # a is an dict with arbitrary contents
b = a.copy()
  1. Che ruolo gioca la mutevolezza delle chiavi e valori dei dicts?
  2. Come faccio a garantire modifiche alle chiavi o valori di una dict non si riflettono in un altro?
  3. Come questo si riferisce al hashable vincolo del chiavi dict?
  4. Ci sono differenze di comportamento tra Python 2.xe 3.x Python?

Come faccio a verificare se un tipo è mutabile in Python?

È stato utile?

Soluzione

1) Le chiavi non deve essere mutevole, a meno che si dispone di una classe definita dall'utente che è hashable, ma anche mutevole. Questo è tutto ciò che è costretto su di voi. Tuttavia, utilizzando un hashable, oggetto mutabile come chiave dict potrebbe essere una cattiva idea.

2) non condividendo i valori tra le due dicts. E 'OK per condividere le chiavi, perché devono essere immutabili. Copiare il dizionario, nel senso del modulo copy, è sicuramente al sicuro. Chiamando il costruttore dict qui funziona anche: b = dict(a). Si potrebbe anche usare valori immutabili.

3) Tutti i tipi built-in immutabili sono hashable. Tutti i tipi built-in mutabili non sono hashable. Per un oggetto da hashable, deve avere lo stesso hash per tutta la sua vita, anche se è mutato.

4) Non che io sappia; Sto descrivendo 2.x.

Un tipo è mutevole, se non è immutabile. Un tipo è immutabile se si tratta di un tipo built-in immutabili: str, int, long, bool, float, tuple, e probabilmente un paio di altri che sto dimenticando. I tipi definiti dall'utente sono sempre mutevoli.

Un oggetto è mutevole, se non è immutabile. Un oggetto è immutabile se costituita, in modo ricorsivo, di sub-oggetti solo immutabili tipizzati. Così, una tupla di liste è mutevole; Non è possibile sostituire gli elementi della tupla, ma è possibile modificare attraverso l'interfaccia lista, modifica dei dati in generale.

Altri suggerimenti

Non è in realtà una cosa come la mutevolezza o immutabilità a livello di lingua in Python. Alcuni oggetti non forniscono alcun modo per cambiare loro (ad esempio stringhe e tuple.), E così sono efficace immutabile, ma è puramente concettuale; non c'è alcuna proprietà a livello di linguaggio che indica questo, né il codice né di Python stesso.

L'immutabilità non è in realtà rilevante per dicts; è perfettamente bene di utilizzare i valori mutevoli come chiavi. Ciò che conta è il confronto e l'hashing: l'oggetto deve rimanere sempre uguale a se stesso. Ad esempio:

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)]

Qui, example è non immutabili; stiamo modificando con a.data = 2. Tuttavia, stiamo usando come chiave di un hash senza alcuna difficoltà. Perché? La proprietà Stiamo cambiando non ha alcun effetto sulla parità:. L'hash è invariato, e example(1) è sempre uguale a example(1), ignorando tutte le altre proprietà

L'uso più comune di questo è caching e Memoizzazione:. Avere una proprietà in cache o no non cambia logicamente l'oggetto, e di solito non ha alcun effetto sulla parità

(ho intenzione di fermarsi qui -. Si prega di non chiedere cinque domande in una sola volta)

Ci sono MutableSequence, MutableSet, MutableMapping nel modulo collezioni . Che possono essere utilizzati per controllare mutevolezza dei tipi predefiniti.

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

Se si desidera utilizzare questo su tipi definiti dall'utente, il tipo deve essere uno ereditato da uno di essi o registrato come sottoclasse virtuale.

class x(MutableSequence):
    ...

o

class x:
    ...

abc.ABCMeta.register(MutableSequence,x)

Non c'è davvero alcun garanzia che un tipo che è hashable è anche immutabile, ma almeno, in modo corretto attuazione __hash__ richiede che il tipo è immutabile, per quanto riguarda il proprio hash, e per l'uguaglianza. Questo non viene applicata in alcun modo particolare.

Tuttavia, siamo tutti adulti. Non sarebbe saggio per implementare __hash__ a meno che non serio. In parole povere, questo si riduce appena giù a dire che, se un tipo di realtà può essere utilizzato come chiave del dizionario, allora è destinato ad essere utilizzato in questo modo.

Se siete alla ricerca di qualcosa che è come un dict, ma anche immutabile, quindi namedtuple potrebbe essere la soluzione migliore da ciò che è nella libreria standard. Certo non è una buona approssimazione, ma è un inizio.

  1. dict tasti deve essere hashable, che implica hanno un immutabile hash di valore. dict Valori può o non può essere mutabile; tuttavia, se sono mutabili questo impatti tua seconda domanda.

  2. "Le modifiche ai tasti" non si rifletteranno tra i due dicts. Modifiche a valori immutabili, come le stringhe inoltre non saranno riflesse. Modifiche agli oggetti mutabili, come le classi definite dall'utente saranno riflessi perché l'oggetto è memorizzato da id (cioè riferimento).

    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. Credo che questo si spiega con le prime due risposte.

  4. Non che io sappia a questo riguardo.

alcune riflessioni aggiuntive :

Ci sono due cose principali da sapere per comprendere il comportamento di i tasti : le chiavi devono essere hashable (i quali mezzi attuano object.__hash__(self) ) e devono anche essere "comparabili" (che significa attuano qualcosa come object.__cmp__(self) ). Un importante take-away dalla documentazione: per impostazione predefinita, le funzioni di hash oggetti definiti dall'utente ritorno id() .

Si consideri questo esempio:

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!

Valori sono molto più facili da capire, i negozi dict riferimenti agli oggetti. Leggere le sezioni su hashable. Cose come le stringhe sono immutabili, se si "cambiamento" di loro, il dict è stata modificata in ora fa riferimento a un nuovo oggetto. Oggetti che sono mutevoli possono essere "cambiati in-place", quindi il valore di entrambi dicts cambierà.

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.

In ogni caso, ecco i punti principali di tutto questo:

  • per i tasti , potrebbe non essere mutevolezza , ma hashability e la comparabilità , che vi preoccupate.
  • Vi preoccupate per mutevolezza dei valori, perché, per definizione, il valore di un oggetto mutabile può essere modificato senza cambiare il riferimento ad esso.

Non credo ci sia un modo generale alla prova di uno di questi punti. I test per l'idoneità sarebbe dipenderà dal vostro caso d'uso. Ad esempio, può essere sufficiente per verificare che un oggetto fa o non implementa le funzioni __hash__ e confronto (__eq__ o __cmp__). Come-saggio, si potrebbe essere in grado di "controllo" il metodo __setattr__ di un oggetto in qualche modo per determinare se è mutevole.

Dicts sono insiemi ordinati di coppie chiave: valore. Le chiavi devono essere immutabile, e quindi hashable. Per determinare se un oggetto è hashable, è possibile utilizzare la funzione di hash():

>>> 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'

I valori, d'altro canto, può essere qualsiasi oggetto. Se avete bisogno di controllare se un oggetto è immutabile, quindi vorrei usare hash().

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top