有没有一种方法可以__init__.py将多个文件组织到一个 模块中 ?
__init__.py
原因:模块比软件包更易于使用,因为它们没有太多的命名空间层。
通常情况下,它会打包,这是我得到的。问题出在包上,“导入包”给了我一个空的命名空间。然后,用户必须使用“ fromthepackage import *”(不赞成使用)或确切知道其中包含的内容,然后手动将其拉入可用的名称空间。
我要拥有的是用户“导入包”,并具有漂亮的干净命名空间,如下所示,公开了与项目相关的函数和类以供使用。
current_module \ doit_tools/ \ - (class) _hidden_resource_pool - (class) JobInfo - (class) CachedLookup - (class) ThreadedWorker - (Fn) util_a - (Fn) util_b - (Fn) gather_stuff - (Fn) analyze_stuff
维护人员的工作是避免在不同的文件中定义相同的名称,这在像我一样小的项目时应该很容易。
如果人们能够做到from doit_stuff import JobInfo并让它检索类,而不是包含类的模块,那也将是很好的。
from doit_stuff import JobInfo
如果我所有的代码都在一个巨大的文件中,这很容易,但是我喜欢在事情开始变大时进行组织。我在磁盘上拥有的东西看起来像这样:
place_in_my_python_path/ doit_tools/ __init__.py JobInfo.py - class JobInfo: NetworkAccessors.py - class _hidden_resource_pool: - class CachedLookup: - class ThreadedWorker: utility_functions.py - def util_a() - def util_b() data_functions.py - def gather_stuff() - def analyze_stuff()
我只将它们分开,所以我的文件不是巨大且不可导航的。它们都是相关的,尽管有人(可能是我)可能想自己使用类而不导入所有内容。
我已经在各个主题中阅读了许多建议,这是我可以找到的每个建议的执行方式:
如果 不使用__init__.py,则无法导入任何内容,因为Python不会从sys.path降入该文件夹。
如果 使用blank__init__.py,import doit_tools则为空名称空间,其中不包含任何内容。我的文件均未导入,因此使用起来更加困难。
import doit_tools
如果我在中 列出了子模块__all__,则可以使用(皱眉?)from thing import *语法,但是我所有的类都再次位于不必要的命名空间障碍后面。用户必须(1)知道他们应该使用from x import *而不是import x(2)手动重新洗改类,直到他们可以合理地服从线宽样式约束为止。
__all__
from thing import *
from x import *
import x
如果我在中 添加from thatfile import X语句__init__.py,我会更近一些,但是我有名称空间冲突(?)以及多余的名称空间,用于我不想在其中的东西。在下面的示例中,您将看到:
from thatfile import X
<class 'doit_tools.JobInfo.JobInfo'>
。
current_module \ doit_tools/ \ - (module) JobInfo \ - (class) JobInfo - (class) JobInfo - (module) NetworkAccessors \ - (class) CachedLookup - (class) ThreadedWorker - (class) CachedLookup - (class) ThreadedWorker - (module) utility_functions \ - (Fn) util_a - (Fn) util_b - (Fn) util_a - (Fn) util_b - (module) data_functions \ - (Fn) gather_stuff - (Fn) analyze_stuff - (Fn) gather_stuff - (Fn) analyze_stuff
另外,仅导入数据抽象类的人将得到与从“从doit_tools导入JobInfo”进行操作时期望的结果不同的东西:
current_namespace \ JobInfo (module) \ -JobInfo (class) instead of: current_namespace \ - JobInfo (class)
那么,这是组织Python代码的错误方法吗?如果不是,那么拆分相关代码但仍以类似模块的方式收集代码的正确方法是什么?
也许最好的情况是,“使用doit_tools import JobInfo进行操作”会使使用该软件包的人感到有些困惑?
也许是一个名为“ api”的python文件,以便使用该代码的人们执行以下操作?:
import doit_tools.api from doit_tools.api import JobInfo
===========================================
回应评论的示例:
在python路径中的文件夹’foo’中获取以下软件包内容。
foo/__init__.py
__all__ = ['doit','dataholder','getSomeStuff','hold_more_data','SpecialCase'] from another_class import doit from another_class import dataholder from descriptive_name import getSomeStuff from descriptive_name import hold_more_data from specialcase import SpecialCase
foo/specialcase.py
class SpecialCase: pass
foo/more.py
def getSomeStuff(): pass class hold_more_data(object): pass
foo/stuff.py
def doit(): print "I'm a function." class dataholder(object): pass
做这个:
>>> import foo >>> for thing in dir(foo): print thing ... SpecialCase __builtins__ __doc__ __file__ __name__ __package__ __path__ another_class dataholder descriptive_name doit getSomeStuff hold_more_data specialcase
another_class并descriptive_name在那里杂乱无章,并且在其名称空间下还具有例如doit()的额外副本。
another_class
descriptive_name
如果我在名为Data.py的文件中有一个名为Data的类,那么当我执行“从数据导入数据”时,我将遇到名称空间冲突,因为数据是模块Data内当前名称空间中的一个类,因此当前名称空间。(但是Python似乎能够处理这个问题。)
您可以做到这一点,但这并不是一个好主意,您正在与Python模块/软件包应该工作的方式作斗争。通过在其中导入适当的名称,__init__.py可以使它们在包名称空间中可访问。通过删除模块名称,可以使它们不可访问。(有关为什么需要删除它们的信息,请参阅此问题)。这样一来,您可以通过以下方式接近所需的内容__init__.py:
from another_class import doit from another_class import dataholder from descriptive_name import getSomeStuff from descriptive_name import hold_more_data del another_class, descriptive_name __all__ = ['doit', 'dataholder', 'getSomeStuff', 'hold_more_data']
但是,这将中断随后的尝试import package.another_class。通常,您不能从中导入任何内容,package.module而不package.module能将其作为对该模块的可导入引用进行访问(尽管__all__您可以使用阻塞from package import module)。
import package.another_class
package.module
from package import module
更一般而言,通过按类/函数划分代码,您正在使用Python包/模块系统。Python模块通常应包含要作为一个单元导入的内容。为了方便起见,直接在顶级包名称空间中导入子模块组件并不少见,但是相反的做法是试图隐藏子模块并 仅 允许通过顶级包名称空间访问其内容,这将导致- 问题。另外,尝试“清理”模块的程序包名称空间没有任何好处。这些模块应该位于程序包名称空间中。那就是他们的归属。