V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
zyAndroid
V2EX  ›  Python

python求助

  •  
  •   zyAndroid · 2011-07-09 19:00:51 +08:00 · 5819 次点击
    这是一个创建于 4912 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #!usr/bin/python

    class Person:
    population = 0

    def __init__(self,name):
    self.name=name
    print 'Initializing %s' % self.name
    Person.population += 1

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

    if Person.population == 0:
    print 'I am the last one.'
    else:
    print "There are still %d people left." %Person.population
    print '%s says bye.' % self.name
    wkm = Person("wang")
    ztt = Person("ztt") #第20行

    程序执行结果:
    Initializing wang
    Initializing ztt
    There are still 1 people left.
    wang says bye.
    Exception exceptions.AttributeError: "'NoneType' object has no attribute 'population'" in <bound method Person.__del__ of <__main__.Person instance at 0x7f6eac025368>> ignored

    但是如果将第20行的对象ztt改名之后,也不一定好使,比如,改成zhaoyu之后程序正常运行,
    执行结果如下:
    Initializing wang
    Initializing zhaoyu
    There are still 1 people left.
    zhaoyu says bye.
    I am the last one.
    wang says bye.
    但如果改成z之后,执行结果就又跟ztt的时候一样了。

    也就是说这段程序,出错还是不出错 跟对象名有关,这是为什么呢?

    python版本:Python 2.5.2
    系统信息:Ubuntu 10.04
    11 条回复    1970-01-01 08:00:00 +08:00
    27493586
        1
    27493586  
       2011-07-09 20:44:54 +08:00
    python没缩进你能看懂么
    keakon
        2
    keakon  
       2011-07-09 21:43:42 +08:00
    程序结束时,析构的顺序是不一定的。你手动del wkm和del ztt就正常了。
    ayanamist
        3
    ayanamist  
       2011-07-09 21:46:18 +08:00
    同意@keakon 的观点,python除非手动del,否则__del__方法的调用时机是完全不可知的(一般情况下你不知道gc什么时候会发生),这点和Java里的Finalize方法是一样的。
    keakon
        4
    keakon  
       2011-07-09 21:46:55 +08:00
    还有一种办法就是把__del__里的Person改成self
    noGulaji
        5
    noGulaji  
       2011-07-10 08:58:44 +08:00
    @keakon 如果把__del__里的Person改成self后,self.population的值只加不减了,如下结果:Initializing wang
    Initializing ztt
    There are still 1 people left.
    wang says bye.
    There are still 1 people left.
    ztt says bye.
    keakon
        6
    keakon  
       2011-07-10 09:51:05 +08:00
    那就没办法了,因为在析构对象前,Person类及其成员已经被析构了。
    reus
        7
    reus  
       2011-07-10 11:56:15 +08:00
    试了下,可以用self.__class__.population,运行正常
    因为文档没有提到这点(或者我没找到),所以根据现象猜测下
    Person类没有析构,因为还有对象的属性强reference到它,而只是Person这个name不再reference到该类对象(所以只是减少了reference count,没有到析构条件
    可以验证一下
    先import sys
    然后在__init__里面加入:self.getrefcount = sys.getrefcount
    加入这句是保证在对象析构之前,这个函数都能用(因为可能在对象调用__del__之前,sys模块就被卸掉了
    然后在__del__里面:print self.getrefcount(self.__class__)
    可以看到第一次__del__时,输出5,第二次输出3,所以类是还没有析构的(refcount未到0),只是用Person这个name得不到而已
    reus
        8
    reus  
       2011-07-10 11:58:37 +08:00
    哦,我用的是2.7……2.5不清楚有没有差异
    Hyperion
        9
    Hyperion  
       2011-07-10 12:46:42 +08:00
    =_= 在邮件列表里看到过...

    Class and Object Variables
    (http://www.ibiblio.org/g2swap/byteofpython/read/class-and-object-vars.html)

    相关讨论楼:
    python程序的最后关头,是怎么样的呢?
    (http://groups.google.com/group/python-cn/browse_thread/thread/31df4e6076782599/)
    zyAndroid
        10
    zyAndroid  
    OP
       2011-07-10 13:10:12 +08:00
    @27493586 @Hyperion @reus @keakon @keakon 感谢各位的解答!
    noGulaji
        11
    noGulaji  
       2011-07-11 11:07:22 +08:00
    @reus 确实不错,__class__ 是每个类实例的一个内置属性 (也是每个类的)。它是一个类的引用,而 self 是一个类 (在本例中,是 Person 类) 的实例。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1189 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 23:20 · PVG 07:20 · LAX 15:20 · JFK 18:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.