2009-07-10 16 views
7

Tôi đã suy nghĩ về cách tôi viết các lớp bằng Python. Cụ thể hơn cách constructor được triển khai thực hiện và cách đối tượng bị phá hủy. Tôi không muốn dựa vào tính toán tham chiếu của CPython để làm sạch đối tượng. Điều này về cơ bản cho tôi biết tôi nên sử dụng các câu lệnh để quản lý thời gian sống của đối tượng và tôi cần một phương thức đóng/hủy rõ ràng (phương pháp này có thể được gọi từ __exit__ nếu đối tượng cũng là người quản lý ngữ cảnh).Có thực sự OK để làm đối tượng đóng/xử lý trong __del__?

class Foo(object): 
    def __init__(self): 
     pass 
    def close(self): 
     pass 

Bây giờ, nếu tất cả các đối tượng của tôi cư xử theo cách này và tất cả các mã của tôi sử dụng với những tuyên bố hay các cuộc gọi rõ ràng để close() (hoặc dispose()) Tôi không thực sự thấy cần phải cho tôi để đặt bất kỳ mã trong __del__. Chúng ta có nên sử dụng __del__ để vứt bỏ các vật thể của mình không?

+2

Tôi không muốn dựa vào tính toán tham chiếu của CPython để làm sạch đối tượng. Tại sao trên trái đất không? Có gì sai với tính toán tham chiếu đối tượng? –

+0

@ S.Lott, tính tham chiếu không có ở đó nếu bạn di chuyển mã của mình sang môi trường có bộ sưu tập rác cao cấp hơn, chẳng hạn như Jython hoặc IronPython - và nếu CPython một ngày (ví dụ: thông qua Unladen Swallow) bị kéo và la hét vào thế kỷ 21? Tôi đồng ý với OP về "không dựa vào" RC trong các thư viện di động có thể tái sử dụng của tôi (trái ngược với sử dụng một lần, bỏ đi, các kịch bản và các mô-đun nhỏ). –

+0

@ S.Lott: Alex đã trả lời câu hỏi của bạn. Một lý do tốt khác cho việc muốn không dựa vào việc đếm tham chiếu là JIT sắp ra khỏi dự án PyPy. Những người đứng đằng sau nó có vẻ như là te lạc quan rằng nó sẽ có thể cung cấp up up tốc độ substatial so với CPython. – Arlaharen

Trả lời

13

Câu trả lời ngắn: Số

Long trả lời: Sử dụng __del__ là khó khăn, chủ yếu là bởi vì nó không được bảo đảm đến được gọi. Điều đó có nghĩa là bạn không thể làm những việc ở đó mà hoàn toàn phải được thực hiện. Điều này có nghĩa là chỉ có __del__ về cơ bản chỉ có thể được sử dụng để dọn dẹp sớm hay muộn, như dọn dẹp tài nguyên sẽ được dọn sạch khi quá trình thoát, vì vậy không quan trọng nếu __del__ không được gọi. Tất nhiên, đây cũng là những điều tương tự Python sẽ làm cho bạn. Vì vậy, kinda làm cho __del__ vô dụng.

Ngoài ra, __del__ được gọi khi thu thập dữ liệu Python thu thập và bạn không muốn đợi thu gom rác Pythons, nghĩa là bạn không thể sử dụng __del__.

Vì vậy, không sử dụng __del__. Sử dụng __enter__/__exit__ để thay thế.

FYI: Dưới đây là một ví dụ về một tình huống không tròn nơi destructor không được gọi là:

class A(object): 
    def __init__(self): 
     print('Constructing A') 

    def __del__(self): 
     print('Destructing A') 

class B(object): 
    a = A() 

OK, vì vậy nó là một thuộc tính lớp. Rõ ràng đó là một trường hợp đặc biệt. Nhưng nó chỉ đi để cho thấy rằng đảm bảo rằng __del__ được gọi là không đơn giản. Tôi khá chắc chắn tôi đã nhìn thấy nhiều tình huống không tròn nơi __del__ không được gọi.

+0

Tôi đã hỏi một câu hỏi tương tự cách đây một năm. Cho đến nay, không ai có thể đặt tên cho một kịch bản hợp pháp trong đó phương thức '__del__' sẽ là bất kỳ việc sử dụng nào cả. Theo như tôi đang quan tâm, phương pháp này không bao giờ có trong Python ngay từ đầu. Thật tốt cho không có gì và cho mọi người ấn tượng sai lầm rằng họ có thể sử dụng nó để dọn dẹp. – antred

8

Không nhất thiết. Bạn sẽ gặp phải vấn đề khi bạn có tham chiếu tuần hoàn. Eli Bendersky làm một công việc tốt trong việc giải thích này trong bài viết trên blog của mình:

+0

+1 liên kết rất tốt – dfa

+1

tiếc là bài viết được liên kết rút ra một kết luận sai. '__del__' không được bảo đảm để được gọi. Ở tất cả. Nó không chỉ cho các tài liệu tham khảo theo chu kỳ. Ngoài ra, nó nói ** "Tài liệu tham khảo tuần hoàn, tuy nhiên, thường là một dấu hiệu của thiết kế xấu" ** WTF? – nosklo

0

Nếu bạn chắc chắn sẽ không đi vào tài liệu tham khảo theo chu kỳ, sau đó sử dụng __del__ theo cách đó là OK: càng sớm khi số lượng tham chiếu đến 0, máy ảo CPython sẽ gọi phương thức đó và phá hủy đối tượng.

Nếu bạn dự định sử dụng các tham chiếu tuần hoàn - hãy suy nghĩ kỹ lưỡng và kiểm tra xem các tham chiếu yếu có thể hữu ích hay không; trong nhiều trường hợp, tham chiếu tuần hoàn là một triệu chứng đầu tiên của thiết kế xấu.

Nếu bạn không kiểm soát được đối tượng của mình sẽ được sử dụng, thì việc sử dụng __del__ có thể không an toàn.

Nếu bạn dự định sử dụng JPython hoặc IronPython, __del__ không đáng tin cậy, vì hủy diệt đối tượng cuối cùng sẽ xảy ra trong thu gom rác và đó là điều bạn không thể kiểm soát.

Tóm lại, theo ý kiến ​​của tôi, __del__ thường hoàn toàn an toàn và tốt; tuy nhiên, trong nhiều trường hợp, tốt hơn là nên lùi lại một bước, và cố gắng xem xét vấn đề từ một góc nhìn khác; việc sử dụng tốt thử/ngoại trừ và với ngữ cảnh có thể là một giải pháp sâu sắc hơn.

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