2010-10-15 18 views
8

He programado en Python por un tiempo, y recientemente comencé a usar Ruby en el trabajo. Los idiomas son muy similares. Sin embargo, me encontré con una característica de Ruby que no sé cómo replicar en Python. Es el método de Ruby freeze.Congelar en 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 

¿Hay alguna manera de imitar esto en Python?

EDIT: me di cuenta de que parecía que esto era solo para listas; en Ruby, freeze es un método en Object para que pueda hacer cualquier objeto inmutable. Me disculpo por la confusión.

+0

¿Cuál es el valor de los iterables de "congelación"? –

+0

Puede confiar en que sean los mismos en cualquier caso, en varios subprocesos, etc., y no tiene que preocuparse por el objeto al que se hace referencia en muchos lugares porque no cambiará de debajo de usted. – kerkeslager

Respuesta

9

Siempre podría subclase list y añadir la bandera "congelada" que bloquearía __setitem__ hacer nada:

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 

Luego de jugar con él:

>>> 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! ¡No pensé en usar '__set__' y' __setitem__'! Buena llamada. – kerkeslager

+0

@kerkeslager: ¿cómo resuelve esto su problema de "congelar cualquier objeto"? – SilentGhost

+0

Sí, obviamente esto no es general (pero nada lo es, ya que no existe un mecanismo equivalente y ubicuo en Python), pero debería ser aplicable a cualquier clase de clase si subclasifica y anula mutadores (p. Ej. '__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 

Además, cf. set contra frozenset, bytearray contra bytes.

números, cadenas son a su vez inmutable:

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

Hmm. Puedes congelar cualquier objeto en Ruby, está definido en Object. No creo que esto sea lo mismo. Sin embargo, podría ser suficiente. – steenslag

+0

@steenslag: las variables python son prob diferentes de las variables ruby, por lo tanto, nunca es lo mismo. Los enteros y las cadenas son inmutables en Python, congelar dicts es trivial, como cualquier otro objeto. – SilentGhost

+3

Estaba al tanto de las tuplas y he editado mi pregunta original para aclarar que estoy hablando de todos los objetos. Rechazo su afirmación de que congelar cualquier objeto es trivial en Python. Al menos no es tan trivial como 'obj.freeze()', a menos que haya algo que no sé. – kerkeslager

Cuestiones relacionadas