Неожиданная функциональность print() и os.listdir()

import os

target_dir = "xxx.xxx.xx.xx/path/to/file/dir"
start_seq = "*** Start Sequence ***"
end_seq = "*** End Sequence ***"

def tp_parser(file):
    with open(file) as in_f:
        lines = in_f.readlines()
        f_name = in_f.name[12:16]

        for i, line in enumerate(lines):
            if line.startswith(start_seq):
                start_line = i
            elif line.startswith(end_seq):
                end_line = i

        with open("{0}_Target_Map.txt".format(f_name), "w") as out_f:
            for i, line in enumerate(lines):
                if start_line <= i < end_line:
                    print(line)
                    # out_f.write(line)

for file in os.listdir(os.chdir(target_dir)):
    tp_parser(file)

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

Для этой части:

if start_line <= i < end_line:
    print(line)
    # out_f.write(line)

Если я запускаю скрипт с печатью (строкой), я получаю ошибку «UnboundLocalError: локальная переменная 'end_line', на которую ссылается перед назначением». Однако запуск скрипта с помощью out_f.write(line) работает как положено.

Второй немного менее раздражающей проблемой является эта часть:

for file in os.listdir(os.chdir(target_dir)):
    tp_parser(file)

Я не могу объяснить себе, почему я должен переключаться в рабочий каталог (т.е. os.chdir(target_dir)) для фактического перебора файлов. Я знаю, что os.listdir() сам по себе возвращает список имен файлов, но чем это отличается, если вы передаете аргумент os.chdir() в os.listdir().

Заранее спасибо.


person blackmore5    schedule 05.12.2017    source источник


Ответы (1)


Начиная с конца, вам не нужно переключаться в рабочий каталог для повторения. Я полагаю, вы хотите правильно указать целевой каталог? Таким образом, вы либо меняете каталог на текущий с помощью chdir, либо указываете каталог на listdir. Вы используете первый, но chdir меняет направление как побочный эффект, а не как результат. chdir возвращает None. Таким образом, вы вызываете listdir с None, который по счастливой случайности принимает None как подсказку для использования текущего каталога. Ты можешь написать

os.chdir(target_dir)
for file in os.listdir():
    tp_parser(file)

or

for file in os.listdir(target_dir):
    tp_parser(file)

Что касается первой проблемы, обратите внимание, что вы присваиваете start_line и end_line условным операторам. Я подозреваю, что ваша проблема в том, что иногда одно из условий не выполняется, и использование неназначенного имени позже в коде вызывает ошибку.

Редактировать:

Есть еще одна проблема с этим кодом: вы записываете свой выходной файл в тот же каталог, который вы перечисляете. В следующий раз, когда вы запустите код, код также проанализирует ваш последний выходной файл. Я полагаю, что это не намеренное поведение; но если вы продолжите, вы увидите, что ваши выходные файлы не имеют маркера конца, так как ваше условие для вывода исключает его:

if start_line <= i < end_line: # use of < instead of <= end_line excludes end marker from output

Таким образом, ошибка в этом случае - это просто искажение новых входных файлов, появляющихся среди других. И это случайные совпадения (ошибка пользователя), а не неожиданное поведение кода Python.

person progmatico    schedule 05.12.2017
comment
Спасибо за ответ, очень признателен! Тем не менее, два дополнительных вопроса: 1. Запуск: для файла в os.listdir(target_dir): tp_parser(file) Выдает ошибку, что файл не найден. Я предполагаю, что это произошло из-за попытки вставить строку имени файла в open(file), что побудило меня использовать os.chdir() (либо сверху, либо внутри listdir()) в качестве обходного пути. 2. Я думаю, что вы правы в том, что условие не выполняется, но мне любопытно, почему это не вызовет ту же ошибку при использовании out_f.write(line)? - person blackmore5; 05.12.2017
comment
это просто совпадение, как я и подозревал;), см. мой ответ. - person progmatico; 05.12.2017