Журнал sys.stdout также записывает в ранее созданные файлы - PullRequest
0 голосов
/ 16 октября 2019

У меня есть класс logger в python (= 3.7):

class Logger(object):
    def __init__(self, fpath=None):
        self.console = sys.stdout
        self.file = None
        if fpath is not None:
            mkdir_if_missing(os.path.dirname(fpath))
            self.file = open(fpath, 'w')

    def __del__(self):
        self.close()

    def __enter__(self):
        pass

    def __exit__(self, *args):
        self.close()

    def write(self, msg):
        self.console.write(msg)
        if self.file is not None:
            self.file.write(msg)

    def flush(self):
        self.console.flush()
        if self.file is not None:
            self.file.flush()
            os.fsync(self.file.fileno())

    def close(self):
        self.console.close()
        if self.file is not None:
            self.file.close()

, и я пытаюсь напечатать и записать несколько файлов в цикле for, например:

for i in range(5):
    sys.stdout = Logger(os.path.join('logs', f'log_{i}.log'))
    print('test')

он печатает на консоль правильно, но также продолжает записывать log_0, log_1, .... Поэтому мои распечатанные файлы выглядят так:

log_0.log:

test
test
test
test
test

log_1.log:

test
test
test
test

log_2.log:

test
test
test

log_3.log:

test
test

log_4.log:

test

Я использовал, чтобы исправить это, когда я использовал FileHandlers. Но поскольку нет обработчиков, как я могу закрыть предыдущие файлы и просто записать в новые файлы?

1 Ответ

1 голос
/ 16 октября 2019

Когда вы делаете:

self.console = sys.stdout

, вы сохраняете предыдущий Logger экземпляр в self.console, потому что цикл устанавливает sys.stdout в Logger.

Вы должны использовать атрибут класса, а не атрибут экземпляра, и просто установить его один раз при создании класса.

Вы не должны вызывать self.console.close(), так как это закроет исходный sys.stdout.

class Logger(object):
    console = sys.stdout

    def __init__(self, fpath=None):
        self.file = None
        if fpath is not None:
            mkdir_if_missing(os.path.dirname(fpath))
            self.file = open(fpath, 'w')

    def __del__(self):
        self.close()

    def __enter__(self):
        pass

    def __exit__(self, *args):
        self.close()

    def write(self, msg):
        self.console.write(msg)
        if self.file is not None:
            self.file.write(msg)

    def flush(self):
        self.console.flush()
        if self.file is not None:
            self.file.flush()
            os.fsync(self.file.fileno())

    def close(self):
        if self.file is not None:
            self.file.close()
...