我的Python学习日记(七):Module 模块

本文探讨了Python模块的导入机制,涉及import、模块属性和包的使用,强调了__name__,__file__,__doc__,__package__,__loader__,__spec__,__all__的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我的Python学习日记


DateLog
2023.12.03完成编写

7. Module 模块

7.1 import

2.6 import中我们简单介绍了使用import导入Python自带标准库的方式

  • 其实我们自己也可以自己制作模块,把自己定义的函数、变量等存放在某个.py文件中,这个模块也可以被别的程序引入来使用其中的函数等功能。
  • 一个模块只会被导入一次,不管执行多少次import

当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。

  • 搜索路径是一个解释器会先进行搜索的所有目录的列表,python解释器就会依次从这些目录中去寻找所引入的模块。
  • 搜索路径是在python编译或安装的时候确定的,安装新的库应该也会修改。
  • 搜索路径通常是包含代码文件所在的目录的,如果在当前目录下存在一个与要引入的模块同名的文件,Python就会优先加载该文件,而不是引入你想要的模块,这被称为模块屏蔽,可能会导致引入错误的模块。如果想要避免这种问题,可以重命名引入的模块,为其取一个别名,或者使用绝对路径或相对路径明确指定模块的路径:from . import somemodule

from somemodule import func1

  • 从模块somemodule中导入函数func1,这样可以直接将该函数导入到本文件中,而忽略该模块中其余部分,并且该模块本身也不会进入字符表中
from math import isnan
print(isnan(1)) # False
print(isnan(math.inf)) # NameError name 'math' is not defined
  • 如果直接将整个模块导入,这样并没有把模块中的函数名称写入到当前的符号表中,只是把模块名写入,所以要用模块名称来访问函数
import math
print(math.isnan(1)) # False
print(math.isnan(math.inf)) # False
  • 如果觉得这样很不方便,可以将这些函数本地化:
import math
isnan = math.isnan
inf = math.inf
print(isnan(1)) # False
print(isnan(inf)) # False
  • 每个模块都有各自独立的符号表,所以模块内部的全局变量不会与其他模块或程序的变量搞混。
    模块中也可以导入其他模块,将这些模块放入该模块的字符表中
  • 也可以使用from somemodule import *将somemodule中全部变量和函数(除了_开头的名字),所以该方法一般不使用

7.2 模块内置属性

7.2.1 ' __name__ '

  • 这个属性表示模块的名称
    • import math
      print(math.__name__) # math
      
  • 一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行:
    当一个模块被直接运行时,__name__的值是"__main__",而当模块被导入时,__name__的值是模块的实际名称,所以我们可以利用以下语句来标定:
    • if __name__ == '__main__':
          print('程序自身在运行')
      else:
          print('我来自另一模块')
      

7.2.2 '__file__'

  • 这个属性表示模块的文件路径
    • import mymodule as mm
      print(mm.__file__) # ...\MyBlog\mymodule.py
      
  • 对于内置模块和在交互式环境(命令行等)中执行的代码,__file__可能为None

7.2.3 '__doc__'

  • 文档字符串,通常用于提供对模块的文档、目的、使用方法等信息的描述,有助于提高代码可读性和可维护性
  • 文档字符串位于模块文件顶部,即任何实际代码之前,使用三重(单/双)引号括起
import mymodule as mm
print(mm.__doc__) # 这个模块会输出本模块的名字
  • 如果该字符串前有实际代码,该模块的__doc__为None

7.2.4 '__package__'

  • 这个属性表示模块所属的包
  • 如果不属于任何包,该属性值为None

7.2.5 '__loader__'

  • 这个属性表示用于加载模块的加载器对象,在动态导入时可能会用到。

7.2.6 '__spec__'

  • 这个属性表示模块的规范。模块规范是一个对象,包含有关模块如何加载、实例化和执行的信息。
  • 一般不需要直接操作

7.3 dir()函数

内置的函数dir()可以找到模块内定义的所有名称,以一个字符串列表的形式返回:

import mymodule as mm
print(dir(mm))
# ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'printmodname']

如果没有给定参数,那么dir()函数会罗列出当前定义的所有名称

import mymodule as mm
print(dir())
# ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'mm']

7.4 Package 包

是一种管理模块命名空间的形式,采用“A.B”的命名规则,表示包A中的子模块B

  • 不同包之间的模块重名不会互相影响
  • 包中也可以包含子包
  • 目录中只有包含一个叫做“__init__.py”的文件才会被认作是一个包
    • 最简单情况只需要放一个空的__init__.py文件就可以了,也可以包含一些初始化代码或者为__all__变量赋值
    • 子包同样需要__init__.py文件

在导入包的子模块时,可以直接导入某个特定模块:

import somepackage.somemodule

这种导入方式的问题是每次都需要使用全名访问,如果有子包的话需要输入的更多:

import somepackage.somemodule
somepackage.somemodule.func1()

所以我们可以使用from ... import ...的方式导入:

from mypack import mymodule as mm

这样每次访问就方便多了,我们也可以使用这种方法直接导入这个模块的某个或某些函数或变量

这样调用的模块的__package__属性为其所在的子包:

from mypack.subpack import mymodule as mm
print(mm.__package__) # mypack.subpack

__all__

  • 如果我们使用from mypack import *来导入包中全部模块,python会进入系统一个一个把它们导入进来,但是Windows系统是不区分大小写的系统,所以这样可能导致导入子模块产生模糊,__all__就是用来避免这种情况的
  • __all__写在__init__.py文件中,是一个列表变量,包含了应该被导入的名字的列表
    • __all__ = ["mymodule"]
      
    • 这表示在from mypack.subpack import *时会导入mymodule模块
  • 如果没有定义__all__,但仍要使用from mypack.subpack import *时,就会把这个包里定义的所有内容导入进来,包括__init__.py文件,所以我们需要尽量避免使用这种方式导入模块

__path__
包还提供一个额外的属性__path__,如同模块中的__file__,用来标定包的目录


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HIT-Zxy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值