2014-04-04 66 views
51

此代碼...Python3變量名稱的簡單區別可以改變代碼的運行方式嗎?

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') 

產生以下錯誤......

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

但是這個代碼不。

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') 

我看到的唯一區別是最後一個變量名是「vb」與「v」。

我靠着Python,現在正在OOP的東西上工作。

+2

@StevenRumbalski:總之,是的。但只在口譯員出口處。 –

+6

第一個代碼不會產生該異常。顯示你的完整追蹤。 (更正:它不會在Python 3.3或更高版本中產生這種異常,在3.2中則會產生) – geoffspear

+0

@Wooble Nah!這就是我所缺少的。 – aIKid

回答

59

是的,雖然它不是那麼直接導致這個變量名稱。

當Python退出時,所有模塊也被刪除。模塊清理的方式是將模塊中的所有全局變量設置爲None(以便這些引用不再引用原始對象)。這些全局變量是字典對象中的鍵,並且隨着字典任意排序,重命名一個變量可以改變變量的清除順序。

當您將v更名爲vb時,您更改了變量清除的順序,現在最後清除了Person

一個解決辦法是使用type(self).num_of_people -= 1__del__方法代替:

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

,因爲實例將始終對類的引用還,或測試,如果Person未設置爲None

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

有兩點需要注意:

  • CPython 3.4不再將全局變量設置爲None(在大多數情況下),按照Safe Object Finalization;見PEP 442

  • CPython 3.3自動將randomized hash salt應用於globals字典中使用的str鍵;這使得你觀察到的行爲更加隨機,只是多次重新運行你的代碼可能會或可能不會觸發錯誤消息。

+2

呃..答案很棒,但我不太明白這一點。 'intepreter退出'是什麼意思?你能解釋一下嗎? – aIKid

+3

@aIKid:當Python退出時(或者如果通過刪除所有對它的引用並從'sys.modules'中刪除它,但通常不會這樣做來刪除模塊),將調用模塊__del__,然後繼續首先通過將他們的名字重新命名爲None來清除模塊中的所有全局變量。 –

+0

因此,只有當我們退出解釋器時纔會引發異常。< - 這是錯誤的,對吧? – aIKid

相關問題