函数内部的python导入隐藏现有变量

Ste*_*aan 5 python python-import

我正在处理一个多子模块项目中的一个奇怪的“UnboundLocalError:分配前引用的局部变量”问题,并将其精简为这个片段(使用标准库中的日志模块):

import logging

def foo():
    logging.info('foo')

def bar():
    logging.info('bar')
    if False:
        import logging.handlers
        # With these alternatives things work:
        # import logging.handlers as logginghandlers
        # from logging.handlers import SocketHandler

logging.basicConfig(level=logging.INFO)
foo()
bar()
Run Code Online (Sandbox Code Playgroud)

有这个输出(我试过 python 2.7 和 3.3):

INFO:root:foo
Traceback (most recent call last):
  File "import-test01.py", line 16, in <module>
    bar()
  File "import-test01.py", line 7, in bar
    logging.info('bar')
UnboundLocalError: local variable 'logging' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

显然,即使没有执行导入,函数内部的 import 语句也会隐藏函数作用域中已经存在的同名变量。

这感觉违反直觉和非 Pythonic。我试图找到一些关于此的信息或文档,但到目前为止没有取得太大的成功。有人对这种行为有更多的信息/见解吗?

谢谢

Sin*_*ion 4

你遇到的问题只是重述了 python 处理本地掩码全局变量的相同方式。

要理解它,import foo(大约)是以下语法糖:

foo = __import__("foo")
Run Code Online (Sandbox Code Playgroud)

因此,你的代码是:

x = 1
def bar():
    print x
    if False:
        x = 2
Run Code Online (Sandbox Code Playgroud)

由于名称出现在bar 内logging赋值语句的左侧,因此它被视为局部变量引用,因此 python 不会在该范围内查找同名的全局变量,即使设置它的行永远不能被调用。

处理全局变量的常见解决方法适用:使用您发现的另一个名称,或者:

def bar():
    global logging
    logging.info('bar')
    if False:
        import logging.handlers
Run Code Online (Sandbox Code Playgroud)

这样 python 就不会认为logging是本地的。