2

我正在从这个网页学习Python (它是中文的,请只关注代码。)我想在Windows 7上使用Python 2.7.3自己练习代码。但是我发现对象名称有一个非常奇怪的错误. 代码如下:

class Person:
    '''Represents a person.'''
    population = 0

    def __init__(self, name):
        '''Initializes the person\'s data.'''
        self.name = name
        print '(Initializing %s)' % self.name

        # When this person is created, he/she
        # adds to the population
        Person.population += 1

    def __del__(self):
        '''I am dying.'''
        print '%s says bye.' % self.name

        Person.population -= 1

        if Person.population == 0:
            print 'I am the last one.'
        else:
            print 'There are still %d people left.' % Person.population

    def sayHi(self):
        '''Greeting by the person.
       Really, that\'s all it does.'''
        print 'Hi, my name is %s.' % self.name

    def howMany(self):
        '''Prints the current population.'''
        if Person.population == 1:
            print 'I am the only person here.'
        else:
            print 'We have %d persons here.' % Person.population

David = Person('David')
David.sayHi()
David.howMany()

kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()

David.sayHi()
David.howMany()

运行这些代码时,我收到了这个错误报告(最后两行)。但是当我用“Swaroop”或其他名称替换对象变量“David”时,代码可以正常工作!我不知道这是怎么发生的。

(Initializing David)
Hi, my name is David.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is David.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
David says bye.
Exception AttributeError: "'NoneType' object has no attribute 'population'" in <bound method Person.
__del__ of <__main__.Person instance at 0x00000000026D91C8>> ignored
4

3 回答 3

2

__del__()在解释器关闭期间调用该方法时会出现异常。不能保证此时任何东西都可用,在您的情况下,看起来Person变量已经被破坏了。您应该忽略此问题或停止使用__del__().

于 2013-04-02T09:34:13.273 回答
2

我能找到的唯一解释来自__del__文档(在警告块中):

由于__del__()调用方法的情况不稳定,在执行期间发生的异常将被忽略,sys.stderr而是打印警告。此外,当__del__()响应于模块被删除而被调用时(例如,当程序执行完成时),该方法引用的其他全局变量__del__()可能已经被删除或正在被拆除(例如,导入机器关闭)。

为了验证这一点,我print globals()__del__方法中添加了一个:

  • 第一次调用:Person出现在具有适当类对象的全局变量中

    {'kalam': None, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'Person': <class __main__.Person at 0x00000000021D7168>, '__name__': '__main__', 'David': <__main__.Person instance at 0x00000000022B0748>, '__doc__': None}
    
  • 第二次调用:Person仍然出现,但现在有一个None

    {'kalam': None, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'Person': None, '__name__': None, 'David': None, '__doc__': None}
    

现在,为什么更改变量名David 改变这种行为?

破坏的顺序可能是确定性的,但没有记录规则:我们处于“定义实现”的领域。在这种情况下,在我的特定 Python 解释器上,重命名DavidA确实会改变销毁顺序,并且Person类对象最后被销毁。

这本身不是一个修复,它只是一个奇怪的副作用:你不能合理地依赖破坏顺序。

于 2013-04-02T09:34:29.637 回答
1

__del__显示不被调用的示例:

class Referencer(object):
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print("__del__ {}".format(self.name))

foo = Referencer('foo')
bar = Referencer('bar')
baz = Referencer('baz')
foo.x = bar
bar.x = foo

del foo
del bar
del baz

你会期望这样的输出:

__del__ foo
__del__ bar
__del__ baz

你得到(至少使用 Python 2.7):

__del__ baz
于 2013-04-03T09:36:02.670 回答