有没有更好的方法从Python模块导入变量?

时间:2015-05-21 04:25:48

标签: python import module

首先,情景。我有一个模块config.py:

DEBUG = False    # Set to True with --debug option

另一个使用它的模块do.py:

from config import DEBUG

def do_something():
    if DEBUG:
        print 'Debug...'
    print 'do something'

在main.py中:

import config
import do
import sys

if __name__ == '__main__':
     if len(sys.argv) > 1 and sys.argv[1] == '--debug':
         config.DEBUG = True
     do.do_something()

现在,当我运行它时:

$ python2.7 main.py --debug
do something

所以在do_something()中,DEBUG False

拥有这样的配置标志的最佳方式是:

  1. 作品,
  2. 简明扼要,
  3. 安全吗?

3 个答案:

答案 0 :(得分:1)

解决第1点,我可以这样写do.py:

import config

def do_something():
    if config.DEBUG:
        print 'Debug...'
    print 'do something'

但现在config.DEBUG并不简洁(第2点)。

或者我可以像这样编写config.py:

class Debug(object):
    _DEBUG = False
    def __call__(self):
        return self._DEBUG
    def set(self, debug):
        self._DEBUG = debug
DEBUG = Debug()

但这样可以避免像这样的简单错误:

>>> import config
>>> config.DEBUG()
False
>>> from config import DEBUG
>>> DEBUG()
False
>>> DEBUG.set(True)
>>> DEBUG()
True
>>> DEBUG.set(False)
>>> DEBUG()
False
>>> if DEBUG: print 'Oops'
...
Oops

违反了第3点。

那么还有更好的解决方案吗?

答案 1 :(得分:1)

你拥有的可能是最好的方式。通常,Python中的变量属于某处,而DEBUG属于config,而不是其他任何地方。如果你想将它导入另一个模块,那很好,但你想明确地做,就像你正在做的那样,而不是通过魔术。

值得注意的是,如果您使用DEBUG进行的唯一事情是if DEBUG: print <stuff>,那么使用函数可能会更好:

config.debug(stuff)

此时,您可能需要查看logging,而不是重新发明轮子的三分之一,并希望您不需要另外三分之二。

但是,如果你真的想要“工作,简洁,安全”而不考虑pythonicity或可移植性,还有一个选择:__builtin__模块(在Python 3.x中重命名为builtins。) / p>

在main.py中:

import __builtin__
import do
import sys

if __name__ == '__main__':
     __builtin__.DEBUG = len(sys.argv) > 1 and sys.argv[1] == '--debug'
     do.do_something()

在do.py中,无需导入任何内容:

def do_something():
    if DEBUG:
        print 'Debug...'
    print 'do something'

当然,如果您编写另一个脚本,例如test.py,导入do而不导入main,则会引发NameError。但是,如果您在导入from config import DEBUG之前尝试执行此操作,则会从config.DEBUGmain收到相同的错误,因此情况并非如此。

为什么这样做?来自文档:

  

CPython实现细节:大多数模块都有名称__builtins__(注意's')作为其全局变量的一部分。 __builtins__的值通常是此模块或此模块的__dict__属性的值。由于这是一个实现细节,因此Python的替代实现可能不会使用它。

特别是,每当你import一个模块或运行一个顶级脚本时,除非你用导入钩子做了一些奇怪的事情,执行模块字节码的exec将确保这个发生。这意味着,只要模块不影响DEBUG(当然总是可能)或者使用其全局变量,DEBUG将永远存在于内置字典中。 (如果您exec自己的任何代码明确构建types.ModuleType,并传递显式globals而不是继承它,那么您必须记住做同样的事情,但是希望这不是问题。)

它至少适用于PyPy 2.x和3.x以及Jython 2.5和2.7。除此之外?谁知道;它不能保证。

答案 2 :(得分:0)

我想值得注意的是

from config import DEBUG

在您设置之前导入DEBUGFalse)的值。稍后当您更改它时,您的do模块仍指向旧的False值。如果你想让它更具动态性,你可以在配置中使用一个函数:

# config.py
is_debug = False
def debug():
    return is_debug

然后在do.py

# do.py
from config import debug
def do_something():
    if debug():
        print 'Debug...'
    print 'do something'