2010-10-15 37 views
8

Tôi đã lập trình bằng Python trong một thời gian và gần đây đã bắt đầu sử dụng Ruby tại nơi làm việc. Các ngôn ngữ rất giống nhau. Tuy nhiên, tôi đã gặp một tính năng của Ruby mà tôi không biết cách sao chép bằng Python. Đó là phương pháp freeze của Ruby.Đóng băng bằng 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ó cách nào để bắt chước điều này bằng Python không?

EDIT: Tôi nhận ra rằng tôi đã làm cho nó có vẻ như thế này chỉ dành cho các danh sách; trong Ruby, freeze là một phương thức trên Object để bạn có thể thực hiện bất kỳ đối tượng nào không thay đổi. Tôi xin lỗi vì sự hiểu nhầm.

+0

Giá trị của các lần lặp 'đóng băng' là gì? –

+0

Bạn có thể phụ thuộc vào chúng giống nhau trong mọi trường hợp, trên nhiều luồng, v.v., và không phải lo lắng về đối tượng đang được tham chiếu ở nhiều nơi bởi vì nó sẽ không thay đổi từ bên dưới bạn. – kerkeslager

Trả lời

9

Bạn luôn có thể phân lớp list và thêm "đông lạnh" cờ đó sẽ chặn __setitem__ làm bất cứ điều gì:

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 

Sau đó, chơi với nó:

>>> 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! Tôi không nghĩ đến việc sử dụng '__set__' và' __setitem__'! Cuộc gọi tốt. – kerkeslager

+0

@kerkeslager: Vậy chính xác điều này giải quyết vấn đề "đóng băng bất kỳ đối tượng nào" của bạn? – SilentGhost

+0

Vâng, điều này rõ ràng không phải là chung (nhưng không có gì, như không có cơ chế tương đương, phổ biến trong Python), nhưng nó nên áp dụng cho bất kỳ loại lớp nào nếu bạn phân lớp và ghi đè các trình biến đổi (ví dụ '__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 

Ngoài ra, cf. set so với frozenset, bytearraybytes.

số, dây là bản thân không thay đổi:

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

Hmm. Bạn có thể đóng băng bất kỳ đối tượng nào trong Ruby, nó được định nghĩa trên Object. Tôi không nghĩ rằng điều này là như nhau. Có thể là đủ mặc dù. – steenslag

+0

@steenslag: biến python khác với biến ruby, do đó không bao giờ giống nhau. Các số nguyên và chuỗi là bất biến trong Python, các dicts đóng băng là tầm thường, như bất kỳ đối tượng nào khác. – SilentGhost

+3

Tôi đã nhận thức được bộ dữ liệu và tôi đã chỉnh sửa câu hỏi ban đầu của mình để làm rõ rằng tôi đang nói về tất cả các đối tượng. Tôi phản đối yêu cầu của bạn rằng đóng băng bất kỳ đối tượng nào là tầm thường trong Python. Ít nhất nó không tầm thường như 'obj.freeze()', trừ khi có điều gì đó tôi không biết. – kerkeslager

Các vấn đề liên quan