python对象的生命周期_Python对象生命周期特征

注意:如果你知道任何(非精细的)库代码可以做我想要的,请启发一位C/C++程序员,我会接受这个答案.

我有一个全局变量设置为以下类的实例.它的目的是允许我设置一些手动中断点,在scrapy spider中放置一些快速和脏的printf样式调试点(我特别需要在满足某些条件来调整解析器时断开,有一些非常罕见的输入数据异常) – 改编自this.

Os是OS X 10.8.

import termios, fcntl, sys, os

class DebugWaitKeypress(object):

def __init__(self):

self.fd = sys.stdin.fileno()

self.oldterm = termios.tcgetattr(self.fd)

self.newattr = termios.tcgetattr(self.fd)

self.newattr[3] = self.newattr[3] & ~termios.ICANON & ~termios.ECHO

termios.tcsetattr(self.fd, termios.TCSANOW, self.newattr)

self.oldflags = fcntl.fcntl(self.fd, fcntl.F_GETFL)

fcntl.fcntl(self.fd, fcntl.F_SETFL, self.oldflags | os.O_NONBLOCK)

def wait(self):

sys.stdin.read(1)

def __del__(self):

print "called del"

termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.oldterm)

fcntl.fcntl(self.fd, fcntl.F_SETFL, self.oldflags)

当我按下Ctrl-C并且进程正在展开时,我得到以下异常:

Exception AttributeError: "'NoneType' object has no attribute 'tcsetattr'" in > ignored

我猜错了对象生命周期的机制吗?如何纠正这种情况. AFAIK应该在导入的代码之前销毁任何类实例,不是吗?以声明/定义的相反顺序.

如果终端在进程退出后未被搞砸,我会忽略这一点:D

编辑:

Delian对seth的回答的评论让我明白我需要使用C main()之类的函数,或任何其他函数/生成器,它们作为根函数占主导地位并在那里初始化上下文.这种方式当进程停止时,将调用上下文管理器的__exit__方法.而且我不必在每次wait()调用时重新编程终端流.

虽然重新编程的成本可能并不重要,但了解python中这些基本的C/C++语义是多么好.

编辑2:

Twisted(scrapy使用)在与stdin混淆时会变成apeshit.所以我不得不用文件IO解决问题.

解决方法:

长话短说:__ del__对于这个目的是没用的(而且几乎任何其他目的;你应该忘记它存在).如果要进行确定性清理,请使用上下文管理器.

AFAIK any class instances should be destroyed before the imported code does, no ? in reverse order of declaration/definition.

那是C.算了吧. Python并不关心这一点,实际上它甚至不关心大多数要求这样做的事情.在整个Python语言中没有声明这样的东西,模块级变量存储在本质上是无序的关联数组中.变量不存储对象,它们存储引用(它们不是C引用,它们基本上是没有指针运算的指针) – 对象在堆上,并且不知道关于变量,绑定,语句或语句顺序的事情.

此外,当一个对象被垃圾收集,并且它是否是gc’d时,是未定义的.由于引用计数,你在CPython中获得了一个主要是确定性的图片,但即便如此,它也会在第二个周期中出现.结果是__del__可以在任何时间点被调用(包括模块的一半已被拆除)或根本不被调用.定义__del__相互引用的多个对象也很麻烦,尽管有些GC努力做正确的事情.

最重要的是,在__del__运行时你可以假设很少,所以你做不了多少.你最后一次处理应该通过另一种方法清理过的资源,但事实并非如此,而且就是这样.经验法则:永远不要依赖它来做任何强制性的事情.

相反,创建一个context manager and use it via with.您可以获得确定性清理,而无需担心对象的生命周期.因为,事实上,对象生命周期和资源生命周期是两个完全不同的东西,只是纠缠在C中,因为它是在该环境中进行资源管理的最佳方式.在Python中,RAII不适用,而是我们有:

with as var:

# do something

# "context closed", whatever that means - for resources, usually cleanup

顺便说一句,您可以通过contextlib更方便地定义它(从您的版本快速翻译,可能包含错误或丑陋):

from contextlib import contextmanager

@contextmanager

def debug_wait_keypress():

fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)

newattr = termios.tcgetattr(fd)

newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO

termios.tcsetattr(fd, termios.TCSANOW, newattr)

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)

fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

try:

yield

finally:

termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)

fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

您的等待方法变为自由函数.

标签:python,oop,posix,scrapy

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值