Python相对/绝对导入(再次)

4
这个话题已经被讨论了多次,但我仍然无法使我的软件包工作。 这是情况:我有一个包,其中logging模块负责设置日志记录。 因此,显然,mypackage.logging与Python标准库中的logging产生冲突。
目录结构如下:
├── mypackage
│   ├── __init__.py
│   ├── logging.py
└── script.py

mypackage.__init__

import logging
from . import logging as _logging

logger = logging.getLogger(__name__)

def main():
    _logging.init_logging()
    logger.info("hello")

mypackage.logging

"""logging - Setup logging for mypackage."""

import copy
import logging
import logging.config


_DEFAULT_LOGGING_CONFIG_DICT = {
    'version': 1,

    'formatters': {
        'verbose': {
            'format': '%(asctime)s - %(name)s::%(levelname)s: %(message)s',
        },
        'simple': {
            'format': '-- %(message)s',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'simple',
        },
        'file': {
            'class': 'logging.FileHandler',
            'filename': 'oprpred.log',
            'mode': 'w',
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'oprpred': {
            'level': 'INFO',
        },
    },
    'root': {
        'level': 'INFO',
        'handlers': ['console', 'file'],
    },
}

def init_logging(verbose=False):
    """Initialize logging.

    Set the log level to debug if verbose mode is on.
    Capture warnings.
    """
    d = default_logging_dict()
    if verbose:
        d['root']['level'] = 'DEBUG'
        d['loggers']['oprpred']['level'] = 'DEBUG'
    logging.config.dictConfig(d)
    logging.captureWarnings(True)


def default_logging_dict():
    return copy.deepcopy(_DEFAULT_LOGGING_CONFIG_DICT)

script.py

import mypackage
mypackage.main()

最后,这是我收到的错误消息:

$ python3 script.py                                                                                                                                                                     [11:09:01]
Traceback (most recent call last):
  File "script.py", line 4, in <module>
    mypackage.main()
  File "/Users/benoist/Desktop/test_logging/mypackage/__init__.py", line 8, in main
    _logging.init_logging()
AttributeError: module 'logging' has no attribute 'init_logging'

最后的备注,我注意到如果在 mypackage.__init__.py__ 中,在标准库 logging 之前导入 mypackage.logging,它就能工作。但我不想这样做,因为这违反了 Python PEP8 的建议:

应按以下顺序分组导入:

  1. 标准库导入
  2. 相关的第三方导入
  3. 本地应用/库特定导入
任何帮助都将不胜感激。
Ben.
P.S. 我使用的是Python 3.5.1。

如果您将标准日志记录模块导入为“logging”,并将自己的日志记录模块导入为“logging”,则应该可以正常工作。通常,在“__init_.py”中从自己的包中导入的任何内容都应该使用其真实名称进行导入,并且不应将这些名称与任何其他内容重复。但是,我没有Python 3安装程序可以测试它。 - user2357112
1个回答

0

我处理使用自定义日志模块的特定问题的方式是将所有日志函数导入到我的自定义模块中。现在,您还可以重新实现模块级别的函数,并使用自定义版本。

例如:

"""logging - Setup logging for mypackage."""

import copy
from logging import *
import logging.config


_DEFAULT_LOGGING_CONFIG_DICT = { ... }

def init_logging(verbose=False):
    ...

def default_logging_dict():
    ...

现在你只需要导入自定义模块即可。
from . import logging

log = logging.getLogger()


使用from logging import *的另一种选择是重新实现来自内置logging模块的任何常用函数。

import copy
import logging

def getLogger(*args, **kwargs):
    logging.getLogger(*args, **kwargs)

如果你需要调用尚未重新实现的日志功能,你可以通过内置的logging模块来调用,例如:logging.logging.addLevelName(...)

我猜这个会起作用。对我来说,这似乎是一个“肮脏的技巧”,因为from logging import *非常不安全,因此不建议使用。 - user378147
另一个选项是只使用 import logging,然后重新实现您经常使用的任何函数,特别是 getLogger()。您仍然可以通过调用 (logging.logging.setLevel(...)) 来访问任何日志记录例程。 - amicitas
谢谢你的建议。我很惊讶没有其他人回答这个问题。如果你提出的解决方案是官方的好方法,老实说,我觉得它相当丑陋。我不习惯用Python编写丑陋的解决方案,所以我很惊讶! - user378147

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接