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

6

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

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? 

析构函数是自动调用的,无需在“main”程序/类中添加任何内容吗?
输出:
初始化人员数据 ****************************************** 初始化Rohan ****************************************** 现在人口是:1 嗨,我的名字是Rohan 我在这里是唯一的一个人 初始化人员数据 ****************************************** 初始化Sanjivi ****************************************** 现在人口是:2 如果Person死了: ****************************************** Sanjivi再见世界 还有1个人留下来 我在这里是唯一的一个人 如果Person死了: ****************************************** Rohan再见世界 我是地球上最后一个人 现在人口是:0

你有什么问题吗?如果你能总结一下你的问题,那会帮助我们更好地回答。如果那本书没有帮助到你,还有许多其他可能更有用的书籍。 - S.Lott
就像dclowd9901所说,我想要有人用英语解释构造函数和析构函数——如果我表达不清楚,我很抱歉——我是编程方面的新手——任何帮助都将不胜感激。 - rgolwalkar
这个问题缺乏实际的问题。你也可以写“有人能在这里解释一下Python编程吗?”并粘贴一些其他随机的Python代码 - 这与现在的问题一样毫无意义。 - Jacek Konieczny
我已经粘贴了上面的代码,现在我想知道析构函数是如何被调用的——是自动调用的还是我需要在“main”程序/类中做些什么? - rgolwalkar
长的评论线程和对这个问题的即时反感是对__del__的自然反应,而不是问题本身。"解释 __del__"会让有经验的程序员哭泣。 - Charles Merriam
显示剩余4条评论
2个回答

23

这里是稍微有些主观的回答。

不要使用 __del__。这不是为了析构函数而设计的C++或其他语言。尽管我相信一定会有人能找到一个合理的用例,但是在Python 3.x中,__del__ 方法确实应该被取消。如果你需要使用 __del__,请注意以下基本限制(参见http://docs.python.org/reference/datamodel.html):

  • __del__ 是在垃圾收集器正在收集对象时调用的,而不是在您失去对对象的最后一个引用或执行 del object 时调用。
  • __del__ 负责调用任何超类中的 __del__,虽然不清楚这是按方法解析顺序(MRO)进行还是只是调用每个超类的 __del__
  • 拥有 __del__ 意味着垃圾收集器放弃检测和清理任何循环链接,例如丢失与链表的最后一个引用。您可以从 gc.garbage 中获取被忽略的对象列表。有时候您可以使用弱引用来避免循环,这个问题经常被辩论:参见http://mail.python.org/pipermail/python-ideas/2009-October/006194.html
  • __del__ 函数可以欺骗,保存一个对象的引用,并停止垃圾收集。
  • __del__ 中显式引发的异常会被忽略。
  • __del____init__更多地补充了__new__。这容易让人困惑。有关说明和注意事项,请参见http://www.algorithm.co.il/blogs/index.php/programming/python/python-gotchas-1-del-is-not-the-opposite-of-init/
  • __del__在Python中不是一个"备受喜爱的"函数。您会注意到sys.exit()文档没有指定是否在退出之前进行垃圾回收,并且存在许多奇怪的问题。调用全局变量上的__del__会导致奇怪的排序问题,例如http://bugs.python.org/issue5099。如果__init__失败,是否应该调用__del__?请参见http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423中的长线程。
  • 但另一方面:

    而我个人不喜欢__del__函数的原因是:

    • 每次有人提到__del__,就会陷入三十条混乱的消息中。
    • __del__在Python之禅中违反了以下几点原则:
      • 复杂比复杂好。
      • 特殊情况不足以打破规则。
      • 错误不应该默默传递。
      • 面对模棱两可,拒绝猜测的诱惑。
      • 应该有一种显而易见的方式来解决问题。
      • 如果实现难以解释,那就是个坏主意。
    • 因此,要找到一个不使用__del__的理由。


    2
    太棒了 Charles,虽然它更加技术化,但我现在理解得更好了。最后一个问题:当我创建一个对象时,它真的会被销毁/释放吗?正如你所说,不要使用__del__,那么只做一些微小的函数并让它按照我的意愿工作是否是一个更好的想法呢?提前再次感谢。 - rgolwalkar
    经过深思熟虑,我不得不说我不知道。如果对象没有在顶层声明,那么它会被回收。顶层对象不太明确。对不起。 - Charles Merriam
    谢谢Charles - 你帮助了我很多。 - rgolwalkar
    请注意,自Python3.4+引入PEP 442以来,GC能够在大多数循环中调用__del__。您应该更新有关该点的答案。 - Bakuriu
    抱歉,"GC是否猜测在Python 3.4+的版本中何时调用__del__方法"是正确的吗? - Charles Merriam

    1

    根据我早期的CPTS经验,我对它们的理解如下:

    构造函数:构造函数主要用于类中初始化类的值,并提供了一个机会来执行一些基于创建的后台工作。如果在对象创建过程中传入值,则可以在此处处理将这些值分配给类中变量的赋值操作。(在这种情况下,在构造时您正在增加一个跟踪人口数量的变量)。

    析构函数:析构函数清理类。在Python中,由于垃圾收集器,它不像可能留下悬空指针的语言(如C ++)那样重要。(在这种情况下,您正在销毁对象时减少人口变量)。


    感谢Hortinstein提供了简单明了的解释--那么我写的代码是有意义的吗?我使用了“del rohan”--删除对象从而调用析构函数吗? - rgolwalkar
    5
    不,del rohan不会调用析构函数。它将减少rohan对象的引用计数并从该范围中删除名称。如果引用计数达到0,则会调用析构函数。这是一个微妙但重要的区别。 - Ignacio Vazquez-Abrams
    嗯,如果我不使用del rohan,那么我的析构函数def del(self)将根本不会被执行吗?我问这个问题是因为之前我根本没有使用del,所以def del(self)没有任何效果。请纠正我,因为我并没有清楚地理解如果不使用del,这个析构函数是否会自动调用。 - rgolwalkar

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接