2014-04-04 24 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

相关问题