Inexplicable ResourceWarning: unclosed file <_i

2019-08-16 08:38发布

I am finalising moving my code from python2.7 to python3.5 and turned on warnings to check another module.
When using os.popen() I am getting the following error.

ResourceWarning: unclosed file <_io.TextIOWrapper name=3 encoding='UTF-8'>

The number in the above example "name=3" will change, depending on the code but it is always a integer.
This code snippet produces the error and yet no file has been opened, which is in complete conflict with the error message unclosed file.
My environment is Linux using python 3.5.2

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import warnings
import os
warnings.simplefilter('default')
sink_list = os.popen('pacmd list-sinks | grep "name:" | cut --delimiter=: -f2').readlines()
print (sink_list)
sink = os.popen('pacmd list | grep "Default sink name" | cut --delimiter=: -f2').readline()
print(sink)

Results in the following:

test.py:6: ResourceWarning: unclosed file <_io.TextIOWrapper name=3 encoding='UTF-8'>
  sink_list = os.popen('pacmd list-sinks | grep "name:" | cut --delimiter=: -f2').readlines()
[' <alsa_output.pci-0000_00_1b.0.analog-stereo>\n', ' <fs2-Equaliser>\n', ' <fs2-bs2b>\n']
test.py:8: ResourceWarning: unclosed file <_io.TextIOWrapper name=3 encoding='UTF-8'>
  sink = os.popen('pacmd list | grep "Default sink name" | cut --delimiter=: -f2').readline()
 fs2-Equaliser

Does anyone know why this warning is issued, especially in this circumstance, where no file has been opened?

1条回答
萌系小妹纸
2楼-- · 2019-08-16 09:39

The integer is a file descriptor, the integer number the OS uses to talk about file handles assigned to a process. 0, 1 and 2 are stdin, stdout and stderr, 3 and up are further file descriptors used.

You get the resource warning because you open the file handle, but never close it explicitly. You instead just call .readlines() or .readline() on the Python file object wrapper:

sink_list = os.popen('pacmd list-sinks | grep "name:" | cut --delimiter=: -f2').readlines()

This leaves the file object to be closed by the garbage collector, and you get the warning. You can use the open object as a context manager to have it closed for you:

 with os.popen('pacmd list-sinks | grep "name:" | cut --delimiter=: -f2') as list_sinks:
    sink_list = list_sinks.readlines()

Personally, I'd use the subprocess module to handle external processes, and use Python to do the line selection. This lets you avoid spinning up a separate sh process and generally has much nicer exception handling:

import subprocess

# read list of sinks
result = suprocess.run(['pacmd', 'list-sinks'], stdout=subprocess.STDOUT, encoding='UTF-8')
sink_list = [l.split(':', 2) for l in result.stdout if 'name:' in l]

# read default sink
result = suprocess.run(['pacmd', 'list'], stdout=subprocess.STDOUT, encoding='UTF-8')
default_sink = next((l.split(':', 2) for l in result.stdout if 'Default sink name' in l), None)
查看更多
登录 后发表回答