Передача дескрипторов python через субмодули - PullRequest
0 голосов
/ 20 февраля 2020

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

Например, если у меня есть такой родительский скрипт:

parent.py

import sys
import logging
from child import child_function

logger = logging.getLogger(__name__)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(10)

for _ in range(2):
    print('1. There was an old man named Michael Finnegan.')
    logger.info('2. He had whiskers on his chin-a-gen.')
    child_function()

child.py

import logging

def child_function():
    logger = logging.getLogger(__name__)
    logger.info('3. The wind came up and blew them in again')
    print('4. Poor old Michael Finnegan, begin again.')

Затем, когда я запускаю parent.py, я получаю:

1. There was an old man named Michael Finnegan.
2020-02-20 11:48:48,646 - __main__ - INFO - 2. He had whiskers on his chin-a-gen.
4. Poor old Michael Finnegan, begin again.
1. There was an old man named Michael Finnegan.
2020-02-20 11:48:48,646 - __main__ - INFO - 2. He had whiskers on his chin-a-gen.
4. Poor old Michael Finnegan, begin again.

Так что мне не хватает третьей строки! Если я добавлю logger в качестве аргумента для child_function () ...

def child_function(parent_logger):
    logger = parent_logger.getChild(__name__)
    logger.info('3. The wind came up and blew them in again')
    print('4. Poor old Michael Finnegan, begin again.')

Тогда я получу ожидаемый результат:

1. There was an old man named Michael Finnegan.
2020-02-20 11:54:10,988 - __main__ - INFO - 2. He had whiskers on his chin-a-gen.
2020-02-20 11:54:10,988 - __main__.child - INFO - 3. The wind came up and blew them in again
4. Poor old Michael Finnegan, begin again.
1. There was an old man named Michael Finnegan.
2020-02-20 11:54:10,988 - __main__ - INFO - 2. He had whiskers on his chin-a-gen.
2020-02-20 11:54:10,988 - __main__.child - INFO - 3. The wind came up and blew them in again
4. Poor old Michael Finnegan, begin again.

Но я подумал о идее getLogger ( главная ) строка должна была автоматически получать root регистраторы. Что я неправильно понял?

1 Ответ

1 голос
/ 20 февраля 2020

Прежде всего, если вам нужен настоящий root регистратор, позвоните getLogger() без каких-либо аргументов.

Для получения дополнительных сведений о том, что будет описано ниже, см. Документацию о том, как модуль logging устанавливает иерархию.

Произошло то, что вы вызвали getLogger(__name__) в parent.py, который автоматически получает указанный c логгер с именем, которому назначен на __name__, а не на сам логгер root (поскольку вы непосредственно выполнили файл parent.py, он становится модулем __main__). Что касается child.py, он был импортирован как child, поэтому __name__ был установлен как child, таким образом, он действительно был на один уровень ниже от регистратора "root" и не имеет никакого другого родителя.

Поскольку модуль logging использует точку (.) в качестве разделителя, это приводит к тому, что вы, возможно, прочитали некоторую рекомендацию по использованию getLogger(__name__) как способа получить общего родителя для детские регистраторы. Можно отметить, что в Python разделитель пространства имен также ., так что __name__, который автоматически доступен для любого данного модуля, будет каноническим именем импорта.

Для иллюстрации на примере, учитывая следующую структуру пакета примера:

.
├── example
│   ├── __init__.py
│   ├── lib.py
│   ├── main.py
│   └── submodule
│       ├── __init__.py
│       ├── demo1.py
│       └── demo2.py
└── setup.py

Внутри example/__init__.py, регистратор может быть настроен как таковой (заимствовать часть вашего примера):

import logging
import sys

logger = logging.getLogger(__name__)
handler = logging.StreamHandler(sys.stdout)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

Это будет в факт установки «родительского» регистратора для всех регистраторов с префиксом 'example.', так как __name__ будет преобразовываться в example, когда другой модуль делает import example.

. Кстати, это также означает, что другие модули, такие как example.main и даже example.submodule.demo1 (которые эти соответствующие модули также приобретут своими регистраторами с тем же кодом, getLogger(__name__)), теперь фактически получат преимущества от обработчика и уровня, которые были установлены их относительными root регистратор сделан внутри example модуля. Аналогично, внутри example/submodule/__init__.py этот модуль может получить общего родителя для всего регистратора с префиксом 'example.submodule.', просто присваивая результат getLogger(__name__) переменной и используя его.

...