当用作上下文管理器时,NpzFile 是否会自行关闭?
Is NpzFile closing itself when used as a context manager?
在 numpy.load()
的文档字符串中,我发现了以下警告:
For .npz
files, the returned instance of NpzFile class must be closed to avoid leaking file descriptors.
我注意到,返回的 NpzFile
对象同时具有 __enter__()
和 __exit__()
方法。
如果我这样使用它会自动关闭它吗:
>>> with numpy.load('my_mile.npz') as data:
... A = data['A']
?
是的。使用 with
语句将关闭类文件对象。这是一个例子,直接来自 the documentation:
with load('foo.npz') as data:
a = data['a']
简答
是的,它会在上下文结束后自动关闭文件对象,因为 NpzFile 对象同时具有 __enter__()
和 __exit__()
方法(参见 here)。
已接受答案的更正
更正已接受的答案(以及 documentation):
应用上下文管理器的正确方法不是with load('foo.npz') as data
而是with numpy.load('foo.npz') as data
。使用前者会导致预期的名称错误:NameError: name 'load' is not defined
.
长答案
在关闭 with expression as var
上下文管理器的范围后,var
仍然作为上下文管理器之外的对象保留。然而,在numpy.load()
的情况下,文件描述符var
在作用域外是不可访问的上下文管理器。
考虑以下示例:
# Creating a dictionary of data to be saved using numpy.savez
data_dict = {'some_string': 'Whosebug',
'some_integer': 10000,
'some_array': numpy.array([0,1,2,3,4])
}
# Saving the data
numpy.savez(file='./data_dict.npz', **data_dict)
# Loading the 'data_dict' using context manager
with numpy.load('data_dict.npz') as dt:
string_ = dt['some_string']
integer_ = dt['some_integer']
array_ = dt['some_array']
# OR
with numpy.load('data_dict.npz') as dt:
dt_ = dict(dt) # if you want the entire dictionary to be loaded as is
如果您现在尝试访问上下文管理器之外的文件描述符,它将简单地 return NpzFile 对象,其内存地址如下:
>>> dt
Out[]: <numpy.lib.npyio.NpzFile at 0x7ffba63bb7c0>
但是,正如所料,您将无法访问它的任何属性。例如,当您执行以下操作时,您会得到 AttributeError
:
>>> dt['some_string']
Out[]: Traceback (most recent call last):
.
.
File ".../site-packages/numpy/lib/npyio.py", line 249, in __getitem__
bytes = self.zip.open(key)
AttributeError: 'NoneType' object has no attribute 'open'
这是因为,在 with 上下文管理器结束后,NpzFile 对象的 self.zip
变量被分配 None
值(参见第一个 URL 中的 def close(self):
上面,在 dunder __exit__()
)
中被调用
注意 1: dt.keys()
returns(如预期)一个 KeysView 对象并执行 list(dt.keys())
给你一个键列表' dt
的姓名:['some_string', 'some_integer', 'some_array']
。但是,仍然无法访问存储在这些键上(在上下文管理器范围内)的值(在上下文管理器范围之外)。
注意 2: 我特意使用了包含 non-numpy-array values 的字典只是为了表明可以存储使用 numpy.savez()
的此类词典。但是,这不是存储此类数据的推荐方法。
在 numpy.load()
的文档字符串中,我发现了以下警告:
For
.npz
files, the returned instance of NpzFile class must be closed to avoid leaking file descriptors.
我注意到,返回的 NpzFile
对象同时具有 __enter__()
和 __exit__()
方法。
如果我这样使用它会自动关闭它吗:
>>> with numpy.load('my_mile.npz') as data:
... A = data['A']
?
是的。使用 with
语句将关闭类文件对象。这是一个例子,直接来自 the documentation:
with load('foo.npz') as data:
a = data['a']
简答
是的,它会在上下文结束后自动关闭文件对象,因为 NpzFile 对象同时具有 __enter__()
和 __exit__()
方法(参见 here)。
已接受答案的更正
更正已接受的答案(以及 documentation):
应用上下文管理器的正确方法不是with load('foo.npz') as data
而是with numpy.load('foo.npz') as data
。使用前者会导致预期的名称错误:NameError: name 'load' is not defined
.
长答案
在关闭 with expression as var
上下文管理器的范围后,var
仍然作为上下文管理器之外的对象保留。然而,在numpy.load()
的情况下,文件描述符var
在作用域外是不可访问的上下文管理器。
考虑以下示例:
# Creating a dictionary of data to be saved using numpy.savez
data_dict = {'some_string': 'Whosebug',
'some_integer': 10000,
'some_array': numpy.array([0,1,2,3,4])
}
# Saving the data
numpy.savez(file='./data_dict.npz', **data_dict)
# Loading the 'data_dict' using context manager
with numpy.load('data_dict.npz') as dt:
string_ = dt['some_string']
integer_ = dt['some_integer']
array_ = dt['some_array']
# OR
with numpy.load('data_dict.npz') as dt:
dt_ = dict(dt) # if you want the entire dictionary to be loaded as is
如果您现在尝试访问上下文管理器之外的文件描述符,它将简单地 return NpzFile 对象,其内存地址如下:
>>> dt
Out[]: <numpy.lib.npyio.NpzFile at 0x7ffba63bb7c0>
但是,正如所料,您将无法访问它的任何属性。例如,当您执行以下操作时,您会得到 AttributeError
:
>>> dt['some_string']
Out[]: Traceback (most recent call last):
.
.
File ".../site-packages/numpy/lib/npyio.py", line 249, in __getitem__
bytes = self.zip.open(key)
AttributeError: 'NoneType' object has no attribute 'open'
这是因为,在 with 上下文管理器结束后,NpzFile 对象的 self.zip
变量被分配 None
值(参见第一个 URL 中的 def close(self):
上面,在 dunder __exit__()
)
注意 1: dt.keys()
returns(如预期)一个 KeysView 对象并执行 list(dt.keys())
给你一个键列表' dt
的姓名:['some_string', 'some_integer', 'some_array']
。但是,仍然无法访问存储在这些键上(在上下文管理器范围内)的值(在上下文管理器范围之外)。
注意 2: 我特意使用了包含 non-numpy-array values 的字典只是为了表明可以存储使用 numpy.savez()
的此类词典。但是,这不是存储此类数据的推荐方法。