【Python】模块与包的组织

模块与包

模块和包是Python项目的核心,这里简单总结一些包和结构和使用。

1. 将模块按层次组织成包

将代码按照一定层次组成成包的形式。一个Python包的形式大致如下:

zzz@ubuntu:~/my_learning$ tree my_project
my_project
├── __init__.py
├── package1
│   ├── a.py
│   ├── b.py
│   └── __init__.py
└── package2
    ├── c.py
    └── __init__.py

2 directories, 6 files

可以看到,包的创建很简单,就是在文件系统中创建一个目录结构,然后在每个目录下定义一个__init__.py文件。此时,就可以使用 import 语句来进行导入。

zzz@ubuntu:~/my_learning$ python3
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_project
>>> import my_project.package1
>>> from my_project.package2 import c
>>> 

__init__.py文件会在模块导入模块时运行,比如,当执行 import my_project.package1.a 时,会在导入 a.py 文件之前,先导入 my_project/__init__.pymy_project/package1/__init__.py 文件。__init__.py文件可以留空,也可以包含代码。

2. 模块的导入

模块的导入最简单的形式就是:

import module as md
from module import A as a

相对名称导入
如果我们需要从包中的一个子模块中导入另一个子模块,可以使用相对名称。

# a.py
class A:
    def __str__(self):
        return "class A object"
# b.py
from . import a 
class B(a.A):
    def __str__(self):
        return "class B object"
# b.py
from ..package1 import a

class C(a.A):
    def __str__(self):
        return "class C object"
...

import 语句中的 ... 语句可以视为指定目录名。 . 表示从当前目录中查找,..package1表示从 ../package1 目录中查找。这两个语法中能在 from XX import X语句中使用。
精确控制导入
用户可以使用 from module import * 语句导入模块或包,如果需要对导入的符号进行精确控制,可以使用变量 __all__ 显式列出可导出的符号名。只有列在 __all__ 中的符号才会被导入。

# c.py
from ..package1 import a


class C(a.A):
    def __str__(self):
        return "class C object"

class D:
    def __str__(self):
        return "class D object"

# Only export 'C'
__all__ = ['C']

可以看到,C 被成功导入,而 D 并没有导入。

zzz@ubuntu:~/my_learning$ python3
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from my_project.package2.c import *
>>> print( C() )
class C object
>>> print( D() )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'D' is not defined
>>> 

3. 将一个模块分解为多个文件

我们可以通过 import my_module 语句导入一个模块,然后就可以通过 my_module.A() 的形式使用模块中的符号。现在,我们需要将 my_module 分解为多个单独的文件,然后仍然可以在通过 my_module.A() 的形式使用已经分解到不同文件中的符号。以 c.py 文件为例

# c.py
from ..package1 import a

class C(a.A):
    def __str__(self):
        return "class C object"

class D:
    def __str__(self):
        return "class D object"

可以使用 import 语句导入:

zzz@ubuntu:~/my_learning$ python3
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_project.package2.c as c
>>> 
>>> print( c.C() )
class C object
>>> print( c.D() )
class D object
>>> 

现在我们将 c.py 分解为两个文件,每个文件包含一个类的定义。首先,将c.py 替换成 目录 c,变成如下形式:
修改前:

zzz@ubuntu:~/my_learning/my_project$ tree package2
package2
├── c.py
└── __init__.py

修改后:

package2
├── c
│   ├── c.py
│   ├── d.py
│   └── __init__.py
└── __init__.py

其中:

# my_project/package2/c/c.py 
from my_project.package1 import a

class C(a.A):
    def __str__(self):
        return "class C object
# my_project/package2/c/d.py 
class D:
    def __str__(self):
        return "class D object"

此时,可以使用 import 语句导入 c 模块,但是调用失败。

zzz@ubuntu:~/my_learning$ python3
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_project.package2.c as c
>>> print( c.D() )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'my_project.package2.c' has no attribute 'D'
>>> print( c.C() )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'my_project.package2.c' has no attribute 'C'
>>> 

为解决这个问题,可以在 my_project/package2/c/__init__.py 文件中绑定两个文件。

# my_project/package2/c/__init__.py
from .c import C
from .d import D

此时,就可以在拆分后,仍然可以向之前一样使用:

zzz@ubuntu:~/my_learning$ python3
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_project.package2.c as c
>>> print( c.C() )
class C object
>>> print( c.D() )
class D object
>>> 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值