类CumulativeSender
在应用程序结束时发送电子邮件。我阅读了有关垃圾收集器和__del__
的问题,我想知道是否存在__del__
staticCumulativeSenderObject
在应用程序结束时不会被调用的情况以及为什么?
CumulativeSender.py:
import smtplib;
_staticCumulativeSenderObject = None;
class CumulativeSender(object):
def __init__(self):
recipients['sender'] = 'from@domain.com';
recipients['emails'] = ['to@domain.com'];
recipients['subject'] = 'Test Email';
recipients['smtp_host'] = 'localhost';
self.message = "";
self.fromaddr = recipients['sender'];
self.toaddrs = recipients['emails'];
self.subject = recipients['subject'];
self.server = smtplib.SMTP(recipients['smtp_host']);
def __del__(self):
if(self.message):
msg = ("From: %s\r\nTo: %s\r\n" % (self.fromaddr, ", ".join(self.toaddrs))) + "Subject: " + self.subject + "\r\n\r\n" + self.message;
self.server.sendmail(self.fromaddr, self.toaddrs, msg);
self.server.quit();
def immediateSend():
global _staticCumulativeSenderObject;
if(_staticCumulativeSenderObject is not None):
toDelete = _staticCumulativeSenderObject;
_staticCumulativeSenderObject = None;
del toDelete;
immediateSend = staticmethod(immediateSend);
def addEvent(msg):
global _staticCumulativeSenderObject;
if(_staticCumulativeSenderObject is None):
_staticCumulativeSenderObject = CumulativeSender();
_staticCumulativeSenderObject.message += msg + "\r\n";
addEvent = staticmethod(addEvent);
def addAlert(msg, code = None):
CumulativeSender.addEvent(buildMessage("Allert",msg,code));
addAlert = staticmethod(addAlert);
def addError(msg, code = None):
CumulativeSender.addEvent(buildMessage("Error",msg,code));
addError = staticmethod(addError);
简单使用:
import CumulativeSender;
CumulativeSender.CumulativeSender.addAlert("alert1", 345);
CumulativeSender.CumulativeSender.addAlert("alert2", 346);
或许还有另一种方法可以做我想要的事情?
答案 0 :(得分:2)
好吧,你永远不应该继续__del__
。但你的问题是“什么时候不会调用__del__
方法?”。这实际上很简单,只要你有一个指向你的对象的循环引用。在这种情况下,Python无法区分应首先删除哪个对象,因此Python根本不会调用任何__del__
方法。更难的问题是,当你实际上可以获得循环引用时,但这并不能解决你的问题。
__del__
方法的错误使用通常来自trying to use RAII technique。
你的代码运行良好,直到有人从循环引用中涉及的对象引用_staticCumulativeSenderObject
。但即使它看起来像一个私人,没有人应该做任何参考,这是一个糟糕的设计。此代码将完全符合atexit
模块的用途。
import atexit
@atexit.register
def _sendAtExit():
global _staticCumulativeSenderObject
if _staticCumulativeSenderObject:
#do what your __del__ is doing
_staticCumulativeSenderObject.send_and_close()
_staticCumulativeSenderObject=None
答案 1 :(得分:0)
你需要有一个很好的理由来覆盖__del__
。在绝大多数情况下,缺点超过了优点。您可以使用您选择的网络搜索引擎找到大量关于__del__
的阅读材料。
您没有解释为什么您更喜欢隐式方法,而不是添加send()
方法并在您要发送电子邮件时明确调用它。那将是我最终的建议。
但是,相信您确实有充分理由采用隐式方法,您可以通过定义__enter__
和__exit__
方法(或使用{{3}来定义context manager。快捷方式)。用法如下:
with CumulativeSender(...) as sender:
sender.addEvent(...)
sender.add...(...)
sender.add...(...)
退出此块时,将调用__exit__
方法。你可以在那里发送电子邮件。
请注意,如果异常离开该块,也会调用__exit__
,因此如果引发异常(可能不是),您应该决定是否要发送天气。