使用不同对象管理文件打开和关闭职责
Managing file open and close responsibilities with different objects
在 main 方法中,my_object
需要访问 passed_object
的多个成员,包括打开的文件(passed_file = passed_object.create_file()
。例如:
import os
def main():
print('Start of program...')
passed_object = PassedObject()
my_object = MyObject(passed_object)
my_object.use_passed_object()
print('End of program.')
class MyObject(object):
def __init__(self, passed_object):
self.passed_object = passed_object
def use_passed_object(self):
f = self.passed_object.create_file()
print('attribute:')
print(self.passed_object.attr1)
print('contents of first file:')
print(list(f))
class PassedObject(object):
def __init__(self):
self.attr1 = 'some attribute string'
def create_file(self):
path = '/tmp'
files = [file for file in os.listdir(path)
if os.path.isfile(os.path.join(path, file))]
f = open(files[0], 'r')
return f
main()
问题:passed_object
创建了 my_object
所需的文件对象,以及此简单示例中未显示的其他文件对象。如何在 my_object
完成后关闭这些文件对象而不破坏封装?
我看到的潜在解决方案:
不要传递 passed_object
:传递 passed_object.create_file()
和 passed_object.attr1
,然后在 main with open...
中使用上下文管理器。但是,我现在必须将每个 attribute/created 对象传递给 my_class
.
写方法my_object.close_file()
,从main调用。这似乎也破坏了封装,因为 main 不需要知道这一点。
写一个my_object.__del__()
关闭文件的方法。
不用担心关闭它;您的程序在几行后终止。
假设最简单的情况(因为缺少细节):
PassedObject.create_file
只是打开一个文件,returns 它并不保留对它的引用
- 文件的使用仅限于
MyObject.use_passed_object
的范围
解决方法很简单:use_passed_object
完成后关闭文件:
class MyObject(object):
def __init__(self, passed_object):
self.passed_object = passed_object
def use_passed_object(self):
f = self.passed_object.create_file()
try:
print('attribute:')
print(self.passed_object.attr1)
print('contents of first file:')
print(list(f))
finally:
f.close()
或者,由于 passed_object.create_file()
只是返回一个支持上下文管理器接口的 file
对象,您也可以这样做:
def use_passed_object(self):
with self.passed_object.create_file() as f:
print('attribute:')
print(self.passed_object.attr1)
print('contents of first file:')
print(list(f))
在更复杂的情况下(例如返回内置 file
以外的内容),您可以创建自己的上下文管理器,它封装了对 passed_object.create_file()
...
的访问
另一方面,如果文件在其生命周期内被 MyObject
的多个方法使用,您需要一个围绕 MyObject
实例使用的上下文管理器。
为此,您必须:
- 记住
MyObject
它打开了哪些文件(无论如何你都必须这样做才能在多种方法中使用它)
- 执行
MyObject.close
关闭所有这些文件
class MyObject(object):
def close(self):
for file_object in self.opened_files:
file_object.close()
然后实现上下文管理器并为此使用它。
选项 1:使用 contextlib.closing
import contextlib
def main():
print('Start of program...')
passed_object = PassedObject()
with contextlib.closing(MyObject(passed_object)) as my_object:
my_object.use_passed_object()
print('End of program.')
选项 2:在 MyObject
本身
上实现上下文管理器接口
class MyObject(object):
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
def main():
print('Start of program...')
passed_object = PassedObject()
with MyObject(passed_object) as my_object:
my_object.use_passed_object()
print('End of program.')
在 main 方法中,my_object
需要访问 passed_object
的多个成员,包括打开的文件(passed_file = passed_object.create_file()
。例如:
import os
def main():
print('Start of program...')
passed_object = PassedObject()
my_object = MyObject(passed_object)
my_object.use_passed_object()
print('End of program.')
class MyObject(object):
def __init__(self, passed_object):
self.passed_object = passed_object
def use_passed_object(self):
f = self.passed_object.create_file()
print('attribute:')
print(self.passed_object.attr1)
print('contents of first file:')
print(list(f))
class PassedObject(object):
def __init__(self):
self.attr1 = 'some attribute string'
def create_file(self):
path = '/tmp'
files = [file for file in os.listdir(path)
if os.path.isfile(os.path.join(path, file))]
f = open(files[0], 'r')
return f
main()
问题:passed_object
创建了 my_object
所需的文件对象,以及此简单示例中未显示的其他文件对象。如何在 my_object
完成后关闭这些文件对象而不破坏封装?
我看到的潜在解决方案:
不要传递
passed_object
:传递passed_object.create_file()
和passed_object.attr1
,然后在 mainwith open...
中使用上下文管理器。但是,我现在必须将每个 attribute/created 对象传递给my_class
.写方法
my_object.close_file()
,从main调用。这似乎也破坏了封装,因为 main 不需要知道这一点。写一个
my_object.__del__()
关闭文件的方法。不用担心关闭它;您的程序在几行后终止。
假设最简单的情况(因为缺少细节):
PassedObject.create_file
只是打开一个文件,returns 它并不保留对它的引用- 文件的使用仅限于
MyObject.use_passed_object
的范围
解决方法很简单:use_passed_object
完成后关闭文件:
class MyObject(object):
def __init__(self, passed_object):
self.passed_object = passed_object
def use_passed_object(self):
f = self.passed_object.create_file()
try:
print('attribute:')
print(self.passed_object.attr1)
print('contents of first file:')
print(list(f))
finally:
f.close()
或者,由于 passed_object.create_file()
只是返回一个支持上下文管理器接口的 file
对象,您也可以这样做:
def use_passed_object(self):
with self.passed_object.create_file() as f:
print('attribute:')
print(self.passed_object.attr1)
print('contents of first file:')
print(list(f))
在更复杂的情况下(例如返回内置 file
以外的内容),您可以创建自己的上下文管理器,它封装了对 passed_object.create_file()
...
另一方面,如果文件在其生命周期内被 MyObject
的多个方法使用,您需要一个围绕 MyObject
实例使用的上下文管理器。
为此,您必须:
- 记住
MyObject
它打开了哪些文件(无论如何你都必须这样做才能在多种方法中使用它) - 执行
MyObject.close
关闭所有这些文件
class MyObject(object):
def close(self):
for file_object in self.opened_files:
file_object.close()
然后实现上下文管理器并为此使用它。
选项 1:使用 contextlib.closing
import contextlib
def main():
print('Start of program...')
passed_object = PassedObject()
with contextlib.closing(MyObject(passed_object)) as my_object:
my_object.use_passed_object()
print('End of program.')
选项 2:在 MyObject
本身
class MyObject(object):
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
def main():
print('Start of program...')
passed_object = PassedObject()
with MyObject(passed_object) as my_object:
my_object.use_passed_object()
print('End of program.')