可以依赖引用计数来关闭Python中的文件吗?

2024-09-19 14:30:41 发布

您现在位置:Python中文网/ 问答频道 /正文

在这个问题“Generating an MD5 checksum of a file”中,我的代码是:

import hashlib
def hashfile(afile, hasher, blocksize=65536):
    buf = afile.read(blocksize)
    while len(buf) > 0:
        hasher.update(buf)
        buf = afile.read(blocksize)
    return hasher.digest()

[(fname, hashfile(open(fname, 'rb'), hashlib.sha256())) for fname in fnamelst]

有人批评我在列表理解中打开了一个文件,有人认为,如果我的列表足够长,我会用尽打开的文件句柄。建议使用显著降低hashfile灵活性、hashfile采用文件名参数并使用with的接口。在

这些是必要的吗?我真的做错了什么吗?在

测试此代码:

^{pr2}$

输出结果:

0 7f0346decef0 -> coming into existence.
0 7f0346decef0 <- going away now.
1 7f0346decef0 -> coming into existence.
1 7f0346decef0 <- going away now.
2 7f0346decef0 -> coming into existence.
2 7f0346decef0 <- going away now.
3 7f0346decef0 -> coming into existence.
3 7f0346decef0 <- going away now.
4 7f0346decef0 -> coming into existence.
4 7f0346decef0 <- going away now.
5 7f0346decef0 -> coming into existence.
5 7f0346decef0 <- going away now.
6 7f0346decef0 -> coming into existence.
6 7f0346decef0 <- going away now.
7 7f0346decef0 -> coming into existence.
7 7f0346decef0 <- going away now.
8 7f0346decef0 -> coming into existence.
8 7f0346decef0 <- going away now.
9 7f0346decef0 -> coming into existence.
9 7f0346decef0 <- going away now.
[(0, 139652050636528),
 (1, 139652050636528),
 (2, 139652050636528),
 (3, 139652050636528),
 (4, 139652050636528),
 (5, 139652050636528),
 (6, 139652050636528),
 (7, 139652050636528),
 (8, 139652050636528),
 (9, 139652050636528)]

很明显,每个HereAndGone对象都是随着列表理解的每个元素的构建而创建和销毁的。Python引用计数在没有引用对象时立即释放该对象,这将在计算该列表元素的值之后立即发生。在

当然,也许其他一些Python实现不会这样做。Python实现是否需要进行某种形式的引用计数?从gc模块的文档来看,引用计数显然是该语言的一个核心特性。在

而且,如果我做错了什么,你会建议我重写它,以保持列表理解的简洁明了和界面的灵活性,它可以处理任何可以像文件一样读取的东西?在


Tags: 文件对象列表fnamenowhashergoingbuf
1条回答
网友
1楼 · 发布于 2024-09-19 14:30:41

有人指出了Data Model section of the Python Language Reference,其中非常明确地说“当对象变得不可访问时,不要依赖于对象的立即终结(因此您应该始终显式地关闭文件)。。因此,这就清楚地表明,代码依赖于无法保证的行为。在

即使是,它仍然脆弱。它无形地依赖于文件永远不会被具有循环引用或生存期超过单个文件哈希的数据结构引用。谁知道代码将来会发生什么,以及是否有人会记住这个关键细节?在

问题是该怎么办。问题中的hashfile函数非常灵活,而且似乎很遗憾的是,修改其接口以获取文件名并让它打开函数内部的文件,从而破坏了它的灵活性。我认为最小的解决方案是:

我觉得解决办法是重新考虑一下界面,使其更加通用。在

def hash_bytestr_iter(hasher, bytesiter, ashexstr=False):
    for block in bytesiter:
        hasher.update(bytesiter)
    return (hasher.hexdigest() if ashexstr else hasher.digest())

def iter_and_close_file(afile, blocksize=65536):
    with afile:
        block = afile.read(blocksize)
        while len(block) > 0:
            yield block

我们可以让原始的hashfile使用传入的afile作为上下文管理器,但我觉得这种方式在某种程度上打破了预期。它使hashfile关闭文件,并且它的名称某种程度上保证它将计算哈希,而不是关闭文件。在

我怀疑有很多情况下,当你有一个字节块,并且想把它们都散列成一个连续的块或流的一部分。在字节块上散列迭代器比散列文件更普遍。在

类似地,我认为在很多情况下,你需要迭代一个类似文件的对象,然后关闭它。所以这两个函数都是可重用的和通用的。在

相关问题 更多 >