Необъяснимое предупреждение о ресурсе: закрытый файл <_io.TextIOWrapper name = 3 - PullRequest
0 голосов
/ 01 июля 2018

Я заканчиваю перемещение своего кода с python2.7 на python3.5 и включил warnings, чтобы проверить другой модуль.
При использовании os.popen() я получаю следующую ошибку.

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

Число в приведенном выше примере "name = 3" будет меняться в зависимости от кода, но это всегда целое число.
Этот фрагмент кода вызывает ошибку, но файл не был открыт, что полностью противоречит сообщению об ошибке unclosed file.
Моя среда Linux с использованием 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)

Результаты следующие:

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

Кто-нибудь знает, почему выдается это предупреждение, особенно в этих обстоятельствах, когда файл не был открыт?

1 Ответ

0 голосов
/ 01 июля 2018

Целое число - дескриптор файла , целое число, которое ОС использует для описания дескрипторов файлов, назначенных процессу. 0, 1 и 2 - это stdin, stdout и stderr, 3 и выше - дополнительные файловые дескрипторы.

Вы получаете предупреждение о ресурсе, потому что вы открываете дескриптор файла, но никогда не закрываете его явно. Вместо этого вы просто вызываете .readlines() или .readline() в обертке объекта файла Python:

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

Это оставляет объект файла закрытым сборщиком мусора, и вы получаете предупреждение. Вы можете использовать открытый объект в качестве менеджера контекста, чтобы закрыть его для вас:

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

Лично я бы использовал модуль subprocess для обработки внешних процессов и использовал Python для выбора строки. Это позволяет избежать ускорения отдельного процесса sh и обычно имеет гораздо более приятную обработку исключений:

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)
...