Python文件句柄存入列表时是复制还是引用?多文件正确关闭的最优方式是什么?
先针对你的第一个问题给出明确答案:
在Python里,当你把file1、file2这类文件对象append到images列表时,存进去的是对象的引用,完全不是复制。简单说,列表里的每个元素和你定义的file1、file2变量指向的是同一个文件句柄。比如你要是在append之后直接调用file1.close(),那列表里对应的那个元素也会变成已关闭的状态,反过来也一样。
接下来聊聊文件关闭的最优方式:
你写的for file in images: file.close()本身是能生效的,但这种写法有个隐患——如果bluesky.send_images执行过程中抛出异常(比如网络问题、格式错误),那后续的close循环就不会执行,这些打开的文件句柄就会泄漏(虽然Python的垃圾回收最终可能会处理,但依赖这个不是好习惯)。
所以更稳妥的方式分两种情况:
情况1:bluesky.send_images必须接收文件对象
这种情况下,我们可以用try-finally块来确保无论发送过程是否成功,所有文件都会被关闭:
images = [] captions = [] if condition1: file1 = open('file1.png', 'rb') images.append(file1) captions.append('file 1') if condition2: file2 = open('file2.png', 'rb') images.append(file2) captions.append('file 2') try: # 尝试发送图片 bluesky.send_images('Image post', images, captions) finally: # 无论上面是否出错,都会执行这里的关闭操作 for file in images: file.close()
finally块里的代码是一定会执行的,这样就彻底避免了句柄泄漏的问题。
情况2:bluesky.send_images可以接收二进制数据(更推荐)
如果这个API支持直接传入图片的二进制内容,那我更建议你用with语句(上下文管理器)先把文件内容读进内存,然后立刻关闭文件。这种方式最安全,也不用手动管理关闭逻辑:
images = [] captions = [] if condition1: with open('file1.png', 'rb') as f: # 一次性读取文件的二进制内容 img_bytes = f.read() images.append(img_bytes) captions.append('file 1') if condition2: with open('file2.png', 'rb') as f: img_bytes = f.read() images.append(img_bytes) captions.append('file 2') bluesky.send_images('Image post', images, captions)
with语句会在代码块结束后自动关闭文件,哪怕读取过程中出了错也一样。这样你的列表里存的是图片的二进制数据,完全不用担心句柄的问题,代码也更简洁可靠。
总结一下:优先确认API是否支持二进制数据,如果可以就用第二种方案;如果必须传文件对象,就用try-finally的方式来确保关闭。
备注:内容来源于stack exchange,提问作者Stefan Gofferje

