构造函数和析构函数是如何工作的?

6 投票
2 回答
11746 浏览
提问于 2025-04-15 20:21

我正在试着理解这段代码:

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

    def __init__(self,name):
          //some statements and population += 1
    def __del__(self):
          //some statements and population -= 1 
    def sayHi(self):
        '''grettings from person'''
        print 'Hi My name is %s' % self.name

    def howMany(self):
        '''Prints the current population'''
        if Person.population == 1:
            print 'i am the only one here'
        else:
            print 'There are still %d guyz left ' % Person.population
rohan = Person('Rohan')
rohan.sayHi()
rohan.howMany()


sanju = Person('Sanjivi')
sanju.howMany()

del rohan # am i doing this correctly? 

这个析构函数是怎么被调用的?是自动调用的,还是我需要在“主”程序/类中像上面那样添加什么东西?

输出结果:

正在初始化个人数据
******************************************
正在初始化罗汉
******************************************
现在的人口是:1
嗨,我叫罗汉
我是这里唯一的人
正在初始化个人数据
******************************************
正在初始化桑吉维
******************************************
现在的人口是:2
如果有人去世:
******************************************
桑吉维再见,世界
现在还有1个人
我是这里唯一的人
如果有人去世:
******************************************
罗汉再见,世界
我是地球上最后一个人
现在的人口是:0

如果需要的话,我可以把整个课程的内容也贴上来。我正在学习的内容来自: http://www.ibiblio.org/swaroopch/byteofpython/read/

2 个回答

1

根据我早期的CPTS经验,以下是我的理解:

构造函数:构造函数主要用于类中,用来初始化类的值,并且在创建对象时可以做一些后台工作。如果你在创建对象的时候传入了一些值,这里就是把这些值分配给类里面的变量的地方。(在这个例子中,创建对象时你会增加一个变量,这个变量用来记录人口数量)。

析构函数:析构函数用来清理类。在Python中,由于有垃圾回收机制,这个功能没有像C++那样重要,因为C++可能会留下悬挂指针。(在这个例子中,当对象被销毁时,你会减少人口数量的变量)。

23

这里有一个稍微带点个人观点的回答。

不要使用 __del__。这不是 C++ 或者其他专门为析构函数设计的语言。其实在 Python 3.x 中,__del__ 方法应该被淘汰,尽管我相信总会有人找到合适的使用场景。如果你真的需要使用 __del__,那么要注意以下基本限制,详细信息可以查看 这篇文档

  • __del__ 是在垃圾回收器收集对象时被调用的,而不是在你失去对某个对象的最后引用时,也不是在你执行 del object 时。
  • __del__ 需要负责调用父类中的 __del__,不过这是否按照方法解析顺序(MRO)来调用,还是仅仅调用每个父类,这点并不明确。
  • 如果有 __del__,那么垃圾回收器就会放弃检测和清理任何循环引用,比如失去对链表的最后引用。你可以通过 gc.garbage 获取被忽略的对象列表。有时候可以使用弱引用来避免循环引用。这点时不时会被讨论:可以查看 这篇讨论
  • __del__ 函数可以“作弊”,保存对某个对象的引用,从而阻止垃圾回收。
  • __del__ 中显式抛出的异常会被忽略。
  • __del__ 更像是 __new__ 的补充,而不是 __init__。这点可能会让人感到困惑。可以查看 这篇文章来了解更多和一些注意事项。
  • __del__ 在 Python 中并不是一个“受欢迎”的特性。你会发现 sys.exit() 的文档没有说明在退出之前是否会进行垃圾回收,而且会有很多奇怪的问题。调用全局变量的 __del__ 会导致奇怪的顺序问题,比如 这个问题。如果 __init__ 失败,__del__ 是否应该被调用?可以查看 这条长讨论

但是,另一方面:

  • __del__ 可以确保你不会忘记调用关闭语句。可以查看 这篇文章,它提供了支持 __del__ 的观点。这通常是关于释放 ctypes 或其他特殊资源。

还有我个人不喜欢 __del__ 函数的原因。

  • 每次有人提到 __del__,讨论就会变得混乱,信息量激增。
  • 它违反了 Python 的一些原则:
    • 复杂的东西比复杂的东西更好。
    • 特殊情况并不足以打破规则。
    • 错误不应该悄无声息地过去。
    • 面对模糊的情况,拒绝猜测的诱惑。
    • 应该有一种——最好只有一种——明显的做法。
    • 如果实现难以解释,那就是个坏主意。

所以,找个理由不要使用 __del__

撰写回答