Python游戏世界打怪升级之新手指引十五【模块、包】

模块、包

今天我们来学习一下Python里面的模块和包,在学习之前我们需要首先了解什么是模块,什么是包;下面可以看下它们的定义,

  • 模块

    • 模块是包含Python定义和语句的文件,文件名是py后缀
    • 模块内部,通过全局变量__name__,可以获得模块名
    • 包是通过包.模块名来构造的,也就是一个包可以包含多个模块
    • 里面必须包含__init__.py文件
    • 使用包的好处就是不用担心不同包的作者的模块名一样导致冲突

只看定义可能会很模糊,下面来举例,更加的形象生动

自定义模块

首先创建下面文件

fibo.py

# 斐波那契数列模块

def fib(n):    # 打印斐波那契数列直到 n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()


def fib2(n):   # 返回斐波那契数列直到 n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

这个fibo.py就是一个模块,我们可以在CMD命令行中进行引入,从而使用

注意这个Import fibo,意思就是导入fibo这个模块,从而使用它里面的两个函数;后面讲导入的时候会详细说明

(.venv) PS D:\Code_Study\Python_world> python
Python 3.13.2 (tags/v3.13.2:4f8bb39, Feb  4 2025, 15:23:48) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import fibo
>>> fibo.fib(10)
0 1 1 2 3 5 8
>>> fibo.fib2(10)
[0, 1, 1, 2, 3, 5, 8]
>>> fibo.__name__
'fibo'
>>> fib = fibo.fib
>>> fib2 = fibo.fib2
>>> fib(10)
0 1 1 2 3 5 8
>>> fib2(20)
[0, 1, 1, 2, 3, 5, 8, 13]

以脚本方式执行模块

我们可以在命令行中以python fibo.py <arg>脚本的形式运行模块

(.venv) PS D:\Code_Study\Python_world> python .\fibo.py 20
0 1 1 2 3 5 8 13 
(.venv) PS D:\Code_Study\Python_world> 
  • 首先改造上面的fibo.py文件,发现最下面加入了__name__==__main__的方法;它的作用就是和导入模块一样,但是会把 __name__ 赋值为 "__main__"
  • 添加的代码作用就是,导入sys模块,使用sys.argv[1]接受第一个变量,并且转为int类型,赋值给fib函数
  • 改造后的文件现在既可以当作脚本,也可以用作一个可供导入的模块,因为解析命令行的代码只有在自己执行的时候,才起作用
  • 被其他文件导入的时候,那两行代码就不起作用
# 斐波那契数列模块

def fib(n):  # 打印斐波那契数列直到 n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a + b
    print()


def fib2(n):  # 返回斐波那契数列直到 n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a + b
    return result


if __name__ == '__main__':
    import sys

    fib(int(sys.argv[1]))

除了上面自定义模块之外,Python还提供了一些标准模块供使用;

比如下面的dir()函数,可以查找模块定义的名称,结合上面的fibo.py模块进行使用;

返回结果是经过排序的字符串列表,这里除了会把函数、类、变量找出来

>>> import fibo
>>> dir(fibo)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fib', 'fib2']

可以私下自己去Python官网文档去查阅标准库

模块的搜索路径

Python如何查找模块?它会按照sys.path里面的路径进行顺序查找

  • 当前目录
  • 环境变量PYTHONPATH的目录
  • Python标准库目录
  • 第三方库目录

下面让我们看一下导入又是怎么回事

导入

上面创建了一个模块py文件,下面就可以进行模块的导入的;首先导入有以下几种方式

  • import 模块名
  • from 模块名 import 函数/类/变量
  • from 模块名 import *
  • import 模块名 as 别名;【注意:as也可以适用于上面的情况,但是不包括*的情况】
  • 相对导入,这个放到包后面进行演示

下面让我们结合上面的py文件进行演示

fibo.py
# 斐波那契数列模块

def fib(n):    # 打印斐波那契数列直到 n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()


def fib2(n):   # 返回斐波那契数列直到 n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result
test_fibo.py
# 方法一,直接导入fibo模块
import fibo


if __name__ == '__main__':
    fib = fibo.fib
    fib2 = fibo.fib2

    fib(10)
    print(fib2(20))
    
    
   
# 方法二,从fibo模块导入具体函数(也可以是类、变量)
from fibo import fib, fib2

if __name__ == '__main__':
    # fib = fibo.fib
    # fib2 = fibo.fib2

    fib(10)
    print(fib2(20))
    
    
# 方法三,从fibo模块导入全部
from fibo import *

if __name__ == '__main__':
    # fib = fibo.fib
    # fib2 = fibo.fib2

    fib(10)
    print(fib2(20))
    
    
    
# 方法四,导入fibo模块并且使用别名fb
import fibo as fb

if __name__ == '__main__':
    fib = fb.fib
    fib2 = fb.fib2

    fib(10)
    print(fib2(20))
    

导入其实不复杂,重要的是掌握好模块与模块之间的路径,确保可以被找到就行

包的结构

注意,在使用包的时候,必须要创建一个__init__文件,里面可以没有内容,也可以执行包的初始化代码或设置 __all__ 变量

下面看实例,来自于Python官网文档

假设要为统一处理声音文件与声音数据设计一个模块集(“包”)

sound/                          最高层级的包
      __init__.py               初始化 sound 包
      formats/                  用于文件格式转换的子包
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  用于音效的子包
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  用于过滤器的子包
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...
包的导入和使用

和模块的导入相比,其实就是前面加入了包名,具体看一下例子

import sound.effects.echo
作用就是导入sound下面的effects下面的echo模块,必须通过全名来引用
sound.effects.echo.xxxx(a,b,c,d)


from sound.effects import echo
作用就是从sound下面的effects下面导入echo模块,只需要使用echo就可以引用
echo.xxxx(a,b,c,d)


from sound.effects.echo import echofilter
作用就是从sound下面的effects下面的echo模块,导入echofilter函数、变量、类;可以直接引用
echofilter(a,b,c,d)

不建议从包中导入*

为什么不建议,可以看下下面的例子

from sound.effects import * 

通过目录结构可以发现,effects下面有很多模块,使用的时候会造成浪费时间来查找自己所需要的模块

但是可以通过下面的方法进行解决,就是提供包的显示索引,也就是__init__文件里的__all__变量
运行 from package import * 时,它就是被导入的模块名列表。
__all__ = ["echo", "surround", "reverse"]

如果__init__文件里面定义了一个函数,和__all__变量里面的同名,那么这个就会被函数覆盖,不会被导入进去了

相对导入

这里需要参考上面的包结构,进行使用

  • 一个点【.】表示当前目录
  • 两个点【..】表示上一级目录

假设现在所在的文件是surround模块

from . import echo  .表示当前目录
from .. import formats ..表示上一级目录的formats包
from ..filters import equalizer ..filters表示上一级目录的filters包下面的equalizer
posted @ 2025-03-21 11:29  小鑫仔  阅读(22)  评论(0)    收藏  举报