【问题标题】:Importing from the same library twice pluss version problems从同一个库导入两次加上版本问题
【发布时间】:2013-11-21 00:34:24
【问题描述】:

我有一些代码应该使用 syslog 记录错误。登录到 syslog 时,我希望脚本名称和 pid 显示在日志本身中。

from syslog import syslog, openlog, LOG_PID
from sys import version_info

openlog(logoption=LOG_PID)
syslog('Some message')

然而,python 2.6 不支持 openlog、logoption 和 LOG_PID,而且我知道这个脚本将在使用 python 2.7 和 python 2.6 的机器上运行。我是这样解决的。

from syslog import syslog
from sys import version_info

(major, minor, dummy1, dummy2, dummy3) = version_info
if major == 2 and minor == 7:
    from syslog import openlog, LOG_PID
    openlog(logoption=LOG_PID)

syslog('some message')

这样做感觉很奇怪。这是声音吗?无论如何我可以在 2.6 中获得相同的功能吗?

【问题讨论】:

  • 你至少在这里问问题。问一个具体的问题要好得多。如果您需要提出多个问题,请将它们作为单独的问题提出。
  • 你从哪里得到“python 2.6 不支持 openlog、logoption 和 LOG_PID”的想法?
  • 我进入 python documentation for 2.6 并找不到它。此外,当尝试从 syslog 导入 o​​penlog 和 LOG_PID 时,它会引发错误。
  • openlog 是您刚刚链接的页面上的第二个函数。它在 2.6 文档中与 2.7 文档中的位置完全相同。你怎么会找不到呢? LOG_PID 的文档(两个版本都相同)解释了为什么导入 LOG_PID 失败:如果平台不支持它(也就是说,它不在 <syslog.h> 中),Python 也不支持它.

标签: python python-2.7 python-2.6


【解决方案1】:

第一:

从同一个库导入两次

我不确定您认为问题出在哪里,因为您甚至从未暗示过问题是什么。如果您多次导入一个库,该库实际上只会被导入一次,但作为导入的一部分发生的任何名称绑定每次都会发生。

“但是”通常不是问题,但如果您尝试使用from MODULE import NAME 语法,并且其中一个名称与模块本身具有相同的名称,则很容易混淆自己。

最好的解决办法就是不这样做。例如:

import syslog
# …
syslog.openlog(logoption=syslog.LOG_PID)

如果您确实需要 from 导入,请确保在所有其他 from foo import bar 导入之后只执行 from foo import foo,这样可以避免任何混淆。


接下来,你的基本前提是错误的:

但是,python 2.6 不支持 openlog、logoption 和 LOG_PID

是的。 openlog 函数从一开始就在模块中。所以有LOG_PIDHere are the 2.6 docs。这是我在使用它:

$ python2.6
Python 2.6.7 (r267:88850, Oct 11 2012, 20:15:00)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from syslog import openlog, LOG_PID
>>> openlog('syslog', LOG_PID)

如果您在导入时遇到错误,很可能与 Python 版本无关,而与您的平台有关。正如文档所说,所有日志选项只有“如果在<syslog.h> 中定义”才可用。因此,如果您的平台没有 LOG_PID,那么 Python(无论是 2.6 还是 2.7)在该平台上都不会有 syslog.LOG_PID

确实 2.6 不保证 openlog 接受关键字参数,而 2.7 可以。但这种差异不可能导致ImportError。防止这种情况的方法不仅仅是跳过在 2.6 中调用该函数;它是在没有关键字参数的情况下调用函数,因此它在两个版本中都同样有效。


同时,你说得对,这很奇怪:

(major, minor, dummy1, dummy2, dummy3) = version_info
if major == 2 and minor == 7:

……但这只是因为它过于冗长,而且这取决于version_info 元组在此版本和所有未来版本中始终只有 5 个组件这一事实。这样做的惯用方法是:

if version_info >= (2, 7):

如果您不明白为什么会这样,请阅读Comparisons 上的文档,并尝试比较不同的元组,直到您明白为止。

但是,检查名称而不是检查版本甚至更好。只需try,并使用except 和备用代码处理相关的ImportErrorNameError。 Mateo 的回答显示了如何做到这一点:

try:
    from syslog import syslog, openlog, LOG_PID
    openlog('syslog', LOG_PID)
except ImportError:
    from syslog import syslog

除其他外,这意味着您不必猜测或弄清楚添加了什么版本,也不必冒猜错的风险——就像您在本例中所做的那样。


下一步:

还有没有我可以在 2.6 中获得相同的功能?

当然可以,但不是通过使用 stdlib syslog 模块。它不像 2.6 中的功能,只是对用户隐藏,它不存在。

如果您search PyPI for syslog,您会发现各种可以替代使用的第三方模块。

但如果您的平台的syslog 没有LOG_PID,那么您所做的任何事情都不会让syslog 接受该选项。

您可能希望将loggingSysLogHandler 一起使用,并在Python 级别而不是syslog 级别进行配置。

或者,您可以坚持使用syslog 并手动将 pid 附加到消息上——这是一个可怕的 hack,但是如果平台的 syslog 不记录 pid 而您拒绝使用除 syslog 之外的任何东西,您还能做什么?

【讨论】:

    【解决方案2】:

    我认为你可以使用 try:except 来做到这一点。比如:

    try:
        from syslog import openlog, LOG_PID
        openlog(logoption=LOG_PID)
    except ImportError:
        from syslog import syslog
    

    这使得它不那么特定于版本。

    完全披露:当我尝试做类似的事情时,我从Best way to import version-specific python modules 得到了这个答案。

    【讨论】:

    • 他还想在第一种情况下导入syslog,所以你想在第一行添加, syslog 但是否则,是的,如果这是你想要做的,这就是Pythonic 方法。
    猜你喜欢
    • 2017-01-22
    • 2012-05-29
    • 2015-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    相关资源
    最近更新 更多