2014-11-22 32 views
6

上下文管理器定义安装/清除功能__enter____exit__。真棒。我想保留一个作为成员变量。当我的类对象超出作用域时,我希望执行此清理。这基本上是我理解的行为是使用C++构造函数/析构函数自动发生的。Python上下文托管成员变量?

class Animal(object): 

    def __init__(self): 
     self.datafile = open("file.txt") # This has a cleanup function 
     # I wish I could say something like... 
     with open("file.txt") as self.datafile: # uh... 

    def makeSound(self): 
     sound = self.datafile # I'll be using it later 

# Usage... 
if True: 
    animal = Animal() 
# file should be cleaned up and closed at this point. 

回答

1

Python没有做C++ - 风格RAII(“资源获取就是初始化”,意思是任何你在构造函数中获取,你在析构函数释放)。实际上,除C++之外,几乎没有没有语言做C++风格的RAII。 Python的上下文管理和with语句要实现这一C++确实有RAII同样的事情不同方式,而大多数其他语言做finally陈述,guard等语句(Python同时finally,当然)。


你是什么意思的“当我的类对象超出范围”?

物体不超出范围;引用(或变量,或名称,无论你喜欢)做什么。在最后一个引用超出范围之后的一段时间(对于CPython来说,这是立即的,除非它涉及参考循环;对于其他实现,通常不会),则该对象将被垃圾收集。


如果你想要做一些清理工作时,你的对象是垃圾回收,您使用的__del__方法。但这很少是你真正想要的。 (事实上​​,有的班级有__del__方法只是为了警告他们忘了清理用户,而不是默默地收拾。)


更好的解决方案是让Animal本身上下文管理,所以它可以管理其他上下文管理器 - 或者只是明确地管理事情。然后,你可以这样写:

if True: 
    with Animal() as animal: 
     # do stuff 
    # now the file is closed 

下面是一个例子:

class Animal(object): 

    def __init__(self): 
     self.datafile = open("file.txt") 

    def __enter__(self): 
     return self 

    def __exit__(self, type, value, traceback): 
     self.datafile.close() 

    def makeSound(self): 
     sound = self.datafile # I'll be using it later 

(刚脱落的__exit__结束像这意味着,呼吁self.datafile.close()后,我们成功地做什么,如果没有异常,或者,如果有一个重新提出同样的例外。所以,你不必写什么明确要做到这一点。)


但通常,如果你打算要将课程转换为上下文管理器,还需要添加明确的close。就像文件一样。一旦你这样做,你真的不需要将Animal加入到上下文管理器中;你可以使用closing

2

我给班close功能,如果它是有道理的,然后使用closing情况管理器:

class MyClass(object): 
    def __init__(self): 
     self.resource = acquire_resource() 

    def close(): 
     release_resource(self.resource) 

,然后用它喜欢:

from contextlib import closing 

with closing(MyClass()) as my_object: 
    # use my_object