将单个python .py文件拆分为多个相互依赖的文件

1 投票
1 回答
808 浏览
提问于 2025-04-17 23:52

我想把我写的一个大Python模块拆分成多个文件,每个文件里放一个函数,这些函数之间可能有依赖关系。下面是我想到的一个简单例子:

首先,这是一个独立的.py模块:

#[/pie.py]
def getpi():
    return pi()

def pi():
    return 3.1416

显然,当我导入并调用这两个函数时,它们都能正常工作。现在我把它们拆分到不同的文件里,并加了一个init.py文件来把它们整合起来:

#[/pie/__init__.py]
from getpi import *
from pi import *
__all__=['getpi','pi']

#[/pie/getpi.py]
def getpi():
    return pi()

#[/pie/pi.py]
def pi():
    return 3.1416

因为getpi()函数依赖于pi()函数,所以按照现在的结构调用它会出现错误:

>>> import pie
>>> pie.getpi()

Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    pie.getpi()
  File "C:\python\pie\getpi.py", line 2, in getpi
    return pi()
NameError: global name 'pi' is not defined

为了解决这个问题,我现在的做法是这样写init.py:

#[/pie/__init__.py]
import os as _os

__all__ = []
for _f in  _os.listdir(__path__[0]):
    if not _f == '__init__.py' and _f.endswith('.py'):
        execfile('%s\\%s'%(__path__[0],_f))
        __all__.append(_os.path.splitext(_f)[0])

这样就可以正常工作了:

>>> import pie
>>> pie.getpi()
3.1416

现在一切都像是在一个单独的.py文件中一样工作。init.py可以包含所有各个函数需要的高级导入(比如numpy、os、sys、glob等)。

我觉得这样组织模块是“对的”。新的函数在下次导入时会自动加载(不需要每次都在init.py里添加)。我可以通过查看目录里的内容,快速了解哪些函数是可以使用的,而且所有东西都按字母顺序整理得很好。

目前我看到的唯一缺点是,只有init.py会被编译成字节码,而其他的.py文件不会。不过加载速度并没有问题,所以我不在乎。此外,我也意识到这可能会在打包时出现问题,但我也不太在意,因为我们的脚本是通过自己的版本控制系统分发的。

这样组织Python模块可以吗?如果不行,那正确的做法是什么呢?

1 个回答

4

“正确”的做法是把需要用到的模块导入到相应的位置:

# pi.py
def pi(): return 3.1417

# getpi.py
from .pi import pi
def getpi(): return pi()

# __init__.py
from .pi import *
from .getpi import *

确保你没有循环依赖。循环依赖是指两个或多个模块互相依赖,这种情况在任何情况下都是不好的。你可以通过将代码抽象到合适的层级来避免这种问题。

撰写回答