2014-04-04 19 views
51

Mã này ...Có thể một sự khác biệt đơn giản trong các tên biến Python3 thay đổi cách mã chạy?

class Person: 
    num_of_people = 0 

    def __init__(self, name): 
     self.name = name 
     Person.num_of_people += 1 

    def __del__(self): 
     Person.num_of_people -= 1 

    def __str__(self): 
     return 'Hello, my name is ' + self.name 

cb = Person('Corey') 
kb = Person('Katie') 
v = Person('Val') 

Tạo các lỗi sau ...

Exception AttributeError: "'NoneType' object has no attribute 'num_of_people'" in <bound method Person.__del__ of <__main__.Person object at 0x7f5593632590>> ignored 

Nhưng mã này thì không.

class Person: 
    num_of_people = 0 

    def __init__(self, name): 
     self.name = name 
     Person.num_of_people += 1 

    def __del__(self): 
     Person.num_of_people -= 1 

    def __str__(self): 
     return 'Hello, my name is ' + self.name 

cb = Person('Corey') 
kb = Person('Katie') 
vb = Person('Val') 

Sự khác biệt duy nhất tôi thấy là tên biến cuối cùng là "vb" so với "v".

Tôi đang dựa vào Python và hiện đang làm việc trên nội dung OOP.

+2

@StevenRumbalski: Tóm lại, có. Nhưng chỉ ở lối thông dịch. –

+6

Mã đầu tiên không tạo ra ngoại lệ đó. Hiển thị toàn bộ dấu vết của bạn. (Correction: nó không tạo ra ngoại lệ đó trong Python 3.3 hoặc cao hơn. Trong 3.2 nó có.) – geoffspear

+0

@Wooble Nah! Đó là những gì tôi đã mất tích .. – aIKid

Trả lời

59

Có, mặc dù nó không phải là tên biến rất nhiều gây ra điều này, không trực tiếp.

Khi thoát khỏi Python, tất cả các mô-đun cũng sẽ bị xóa. Cách thức mô-đun được làm sạch bằng cách thiết lập tất cả các hình cầu trong một mô-đun thành None (vì vậy các tham chiếu đó không còn tham chiếu đến các đối tượng gốc). Các hình cầu đó là các khóa trong một đối tượng từ điển, và khi các từ điển được sắp xếp một cách tùy ý, việc đổi tên một biến có thể thay đổi thứ tự các biến được xóa.

Khi bạn đổi tên v thành vb, bạn đã thay đổi thứ tự các biến bị xóa và giờ đây Person sẽ bị xóa sau cùng.

Một công việc xung quanh là sử dụng type(self).num_of_people -= 1 trong __del__ phương pháp thay vì:

def __del__(self): 
    type(self).num_of_people -= 1 

vì dụ sẽ luôn luôn có một tham chiếu đến lớp vẫn còn, hoặc kiểm tra nếu Person không được đặt để None:

def __del__(self): 
    if Person is not None: 
     Person.num_of_people -= 1 

Hai lưu ý:

  • CPython 3.4 không còn đặt hình cầu thành None (trong hầu hết các trường hợp), theo Safe Object Finalization; xem PEP 442.

  • CPython 3.3 tự động áp dụng randomized hash salt cho các phím str được sử dụng trong từ điển globals; điều này làm cho hành vi bạn quan sát thậm chí ngẫu nhiên hơn, chỉ chạy lại mã của bạn nhiều lần có thể hoặc không thể kích hoạt thông báo lỗi.

+2

Ugh .. Câu trả lời là tuyệt vời, nhưng tôi không thực sự hiểu điều này. Bạn có ý gì khi 'vào lối ra intepreter'? Bạn có thể giải thích dùm không? – aIKid

+3

@aIKid: Khi Python thoát, (hoặc nếu bạn xóa mô-đun bằng cách xóa tất cả các tham chiếu đến nó và xóa nó khỏi 'sys.modules', nhưng điều đó thường không được thực hiện), thì mô-đun' __del__' được gọi, sau đó tiếp tục đầu tiên thanh toán bù trừ tất cả các globals trong module bằng cách rebinding tên của chúng thành 'None'. –

+0

Vì vậy, ngoại lệ chỉ được nâng lên khi chúng tôi thoát khỏi trình thông dịch .. <- Đó là sai, phải không? – aIKid

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