4

tl;dr:如何在 some 中创建一个新的命名空间__init__.py,并将另一个命名空间的选择位复制到其中,而不需要在新目录中使用子模块?

完整问题:

假设我在一个包中有一对模块,目录结构如下:

foo/mod_1.py
foo/mod_2.py
foo/__init__.py

mod_1.py如下:

import numpy

__all__ = ['test1']

def test1():
    return numpy.zeros(10)

mod_2.py如下:

import numpy

def test2():
    return numpy.zeros(20)

如下__init__.py

from mod_1 import *
import mod_2

del mod_1

这或多或少产生了所需的命名空间:

In [7]: dir(foo)
Out[7]: 
['__builtins__',
 '__doc__',
 '__file__',
 '__name__',
 '__package__',
 '__path__',
 'mod_2',
 'test1']

除了现在numpyfoo.mod_2命名空间中。如果我尝试在__init__.py, with中删除它del mod_2.numpy,则该模块不再存在,因此mod_2.test2已损坏。

mod_2我可以通过创建一个包含的额外目录来实现我想要的mod_2.py,但如果可能的话,我想保持目录结构不变。

因此,我最初的问题。

编辑:我不介意做一些名字修饰来阻止一个名字踩在另一个名字上。假设将相关位mod_2.py放入foo._mod_2.

4

1 回答 1

3

不想这样做,因为你发现你破坏了你的代码。

Python 是一种动态语言,自省让我们可以不受限制地访问解释器所能访问的几乎所有内容。这也适用于您的模块。

如果它让你感觉更好,同样的事情也适用于标准库:

>>> import unittest
>>> unittest.sys
<module 'sys' (built-in)>
>>> unittest.types
<module 'types' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/types.pyc'>
>>> dir(unittest)
['FunctionTestCase', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'TestSuite', 'TextTestRunner', '_CmpToKey', '_TextTestResult', '_WritelnDecorator', '__all__', '__author__', '__builtins__', '__doc__', '__email__', '__file__', '__metaclass__', '__name__', '__package__', '__unittest', '__version__', '_makeLoader', '_strclass', 'defaultTestLoader', 'findTestCases', 'getTestCaseNames', 'main', 'makeSuite', 'os', 'sys', 'time', 'traceback', 'types']

从外部可以看到模块在其全局命名空间中所需的一切。这是正常的

正如您已经发现的那样,使用__all__来控制from modulename import *通配符导入,否则请单独保留模块名称空间。

当然,如果你想为你的包的用户提供一个干净的 API,没有什么能阻止你将作为 API 一部分的名称导入顶级包__init__.py,或者使用api.py模块。

导入只是意味着在当前模块中添加与变量相同的名称;mod_2.numpy是完全相同的东西sys.modules['numpy'],或者numpy在你运行后的当前模块中import numpy

于 2012-11-29T13:46:12.143 回答