2010-10-15 10 views
8

Ho programmato in Python per un po 'e recentemente ho iniziato a usare Ruby al lavoro. Le lingue sono molto simili. Tuttavia, ho appena trovato una funzionalità di Ruby che non so come replicare in Python. È il metodo freeze di Ruby.Freeze in Python?

irb(main):001:0> a = [1,2,3] 
=> [1, 2, 3] 
irb(main):002:0> a[1] = 'chicken' 
=> "chicken" 
irb(main):003:0> a.freeze 
=> [1, "chicken", 3] 
irb(main):004:0> a[1] = 'tuna' 
TypeError: can't modify frozen array 
     from (irb):4:in `[]=' 
     from (irb):4 

C'è un modo per imitare questo in Python?

EDIT: Ho capito che ho fatto sembrare che fosse solo per le liste; in Ruby, freeze è un metodo su Object in modo da rendere immutabile qualsiasi oggetto. Mi scuso per la confusione.

+0

Qual è il valore di "congelamento" iterable? –

+0

Si può dipendere dal fatto che siano sempre gli stessi, su più thread, ecc., E non bisogna preoccuparsi che l'oggetto venga fatto riferimento in molti posti perché non cambierà da sotto di voi. – kerkeslager

risposta

9

Si può sempre sottoclasse list e aggiungere il flag "congelata", che avrebbe bloccato __setitem__ di fare qualsiasi cosa:

class freezablelist(list): 
    def __init__(self,*args,**kwargs): 
     list.__init__(self, *args) 
     self.frozen = kwargs.get('frozen', False) 

    def __setitem__(self, i, y): 
     if self.frozen: 
      raise TypeError("can't modify frozen list") 
     return list.__setitem__(self, i, y) 

    def __setslice__(self, i, j, y): 
     if self.frozen: 
      raise TypeError("can't modify frozen list") 
     return list.__setslice__(self, i, j, y) 

    def freeze(self): 
     self.frozen = True 

    def thaw(self): 
     self.frozen = False 

Poi giocare con esso:

>>> from freeze import freezablelist as fl 
>>> a = fl([1,2,3]) 
>>> a[1] = 'chicken' 
>>> a.freeze() 
>>> a[1] = 'tuna' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "freeze.py", line 10, in __setitem__ 
    raise TypeError("can't modify frozen list") 
TypeError: can't modify frozen list 
>>> a[1:1] = 'tuna' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "freeze.py", line 16, in __setslice__ 
    raise TypeError("can't modify frozen list") 
TypeError: can't modify frozen list 
>>> 
+0

Ah! Non pensavo di usare '__set__' e' __setitem__'! Buona chiamata – kerkeslager

+0

@kerkeslager: in che modo esattamente questo risolve il problema del "blocco di qualsiasi oggetto"? – SilentGhost

+0

Sì, questo ovviamente non è generale (ma nulla è, poiché nessun meccanismo equivalente ubiquitario in Python è), ma dovrebbe essere applicabile a qualsiasi tipo di classe se si sottoclasse e si sovrascrivono i mutatori (ad esempio '__setitem__',' __setattr__' , '__setslice__') –

11
>>> a = [1,2,3] 
>>> a[1] = 'chicken' 
>>> a 
[1, 'chicken', 3] 
>>> a = tuple(a) 
>>> a[1] = 'tuna' 
Traceback (most recent call last): 
    File "<pyshell#4>", line 1, in <module> 
    a[1] = 'tuna' 
TypeError: 'tuple' object does not support item assignment 

Inoltre, cfr. set vs. frozenset, bytearray vs. bytes.

numeri, stringhe sono essi stessi immutabili:

>>> a = 4 
>>> id(a) 
505408920 
>>> a = 42  # different object 
>>> id(a) 
505409528 
+0

Hmm. Puoi bloccare qualsiasi oggetto in Ruby, è definito su Oggetto. Non penso che sia lo stesso. Potrebbe essere sufficiente però. – steenslag

+0

@steenslag: le variabili python sono probabilmente diverse dalle variabili ruby, quindi non è mai la stessa cosa. Gli interi e le stringhe sono immutabili in Python, il congelamento dei dadi è banale, come qualsiasi altro oggetto. – SilentGhost

+3

Ero a conoscenza delle tuple e ho modificato la mia domanda iniziale per chiarire che sto parlando di tutti gli oggetti. Contestiamo la tua affermazione che il congelamento di qualsiasi oggetto è banale in Python. Almeno non è così banale come 'obj.freeze()', a meno che non ci sia qualcosa che non conosco. – kerkeslager

Problemi correlati