Python模块化

模块化

  • 一般来说,编程语言中,库、包、模块是同一种概念,是代码组织方式
  • 模块module,指的是Python的源代码文件。包package,指的是模块组织在一起的和包名同名的目录及其相关文件

导入语句

语句含义
import 模块1[,模块2,…]完全导入
import … as …模块别名

import语句
1、找到指定的模块,加载和初始化它,生成模块对象。找不到,抛出异常
2、在import所在的作用域的局部命名空间中,增加名称和上一步创建的对象关联

import os.path   #导入os.path,os加入当前名词空间.path不加入名称空间
print(dir())     # [..., 'os']
print(os)
print(os.path)    #完全限定名称访问path
-----------------------------------------------------------------
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'os']
<module 'os' from 'C:\\anaconda\\lib\\os.py'>
<module 'ntpath' from 'C:\\anaconda\\lib\\ntpath.py'>

import os.stat  #不可以运行
  • 总结
    • 导入顶级模块,其名称会加入到本地名词空间中,并绑定到其模块对象。
    • 导入非顶级模块,只将其顶级模块名称加入到本地名词空间中。导入的模块必须使用完全限定名称来访问.
    • 如果使用了as,as后的名称直接绑定到导入的模块对象,并将该名称加入到本地名词空间中。

语句含义
from … import …部分导入
from … import … as …别名
from pathlib import Path,PosixPath  #在当前名词空间(当前模块)导入该模块指定的成员
print(dir())  # ['Path', 'PosixPath',...,]
-----------------------------------------------------------------
['Path', 'PosixPath', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

from pathlib import *  #* 在当前名词空间导入改模块所有的共有成员(非下划线开头的成员),或指定成员
print(dir())['Path', 'PosixPath', 'PurePath', 'PurePosixPath', 'PureWindowsPath', 'WindowsPath']

-----------------------------------------------------------------
['Path', 'PosixPath', 'PurePath', 'PurePosixPath', 'PureWindowsPath', 'WindowsPath', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

from os.path import exists # 加载、初始化os、os.path模块,exists加入本地名词空间并绑定

总结

  • 找到from子句中指定的模块,加载并初始化它(注意不是导入)
  • 对于import子句后的名称
    • 先查from子句导入的模块是否具有该名称的属性
    • 如果不是,则尝试导入该名称的子模块
    • 还没有找到,则抛出ImportError异常
    • 这个名称保存到本地名词空间中,如果有as子句,则使用as子句后的名称

自定义模块

自定义模块命名规范
  • 模块名就是文件名
  • 模块名必须符合标识符的要求,是非数字开头的字母、数字和下划线的组合。不要使用中文。
  • 不要使用系统模块名来避免冲突.
  • 通常模块名为全小写,下划线来分割
模块搜索顺序

使用sys.path查看搜索顺序

import  sys
print(sys.path)
for p in sys.path:
    print(p)
--------------------------------------------
F:\pycharm
C:\anaconda\python37.zip
C:\anaconda\DLLs
C:\anaconda\lib
C:\anaconda
C:\anaconda\lib\site-packages
C:\anaconda\lib\site-packages\win32
C:\anaconda\lib\site-packages\win32\lib
C:\anaconda\lib\site-packages\Pythonwin
  • 路径顺序为
    • 程序主目录,程序运行的主程序脚本所在的目录
    • PYTHONPATH目录,环境变量PYTHONPATH设置的目录也是搜索模块的路径
    • 标准库目录,Python自带的库模块所在目录
模块重复导入

所有加载的模块都会记录在sys.modules中,sys.modules是存储已经加载过的所有模块的字典,不会重复导入

模块运行
  • __name __,每个模块都会定义一个__name __特殊变量来存储当前模块的名称,如果不指定,则默认为源代码文件名,如果是包则有限定名。
  • 解释器初始化的时候,会初始化sys.modules字典(保存已加载的模块),加载builtins(全局函数、常量)模块、__main __模块、sys模块,以及初始化模块搜索路径sys.path
  • 当从标准输入(命令行方式敲代码)、脚本($ python test.py)或交互式读取的时候,会将模块的__name __设置为__main __,模块的顶层代码就在__main __这个作用域中执行。顶层代码:模块中缩进最外层的代码。如果是import导入的,其__name __默认就是模块名

if name == ‘main’:用途
  1. 本模块的功能测试对于非主模块,测试本模块内的函数、类
  2. 避免主模块变更的副作用顶层代码,没有封装,主模块使用时没有问题。但是,一旦有了新的主模块,老的主模块成了被导入模块,由于原来代码没有封装,一并执行了。
# testa.py
if __name__ == '__main__':
    print('in __main__')  # 程序在主模块中运行
else:
    print('in import module')  # 在模块导入的方式运行代码
----------------------------------------
in __main__
    
# testb.pyy
import testa
-------------------------------------------
in import module
模块的属性
属性含义
__file __字符串,源文件路径
__cached __字符串,编译后的字节码文件路径
__spec __显示模块的规范
__name __模块名
__package __当模块是包,同__name __;否则,可以设置为顶级模块的空字符串

Python中,目录可以作为模块,这就是包,不过代码需要写在该目录下__init__.py中

字模块

包目录下的py文件、子目录都是其子模块


绝对导入和相对导入

绝对导入

在import语句或者from导入模块,模块名称最前面不是以.点开头的绝对导入总是去模块搜索路径中找,当然会查看一下该模块是否已经加载

相对导入
  • 只在包内使用,且只能用在from语句中使用
  • .点号,表示当前目录内
  • …表示上一级目录
  • 不要在顶层模块中使用相对导入

注意:一旦一个模块中使用相对导入,就不可以作为主模块运行了


from…import *和__all __

使用from … import * 导入
# testb.py
A = 1
_B = 2
__C = 3
__my __ = 5

#testa.py
from testb import *
import sys

print(sorted(sys.modules.keys()))
print(dir())
print(locals()['A'])
--------------------------------------------------------
testb
['__main__', ......]
['A', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'sys']
1

以上只导入了A,下划线开头的都没有导入

使用__all __

__all __是一个列表,元素是字符串,每一个元素都是一个模块内的变量名

#testa.py
from testb import *
import sys

print(sorted(sys.modules.keys()))
print(dir())
print(locals()['A'])
---------------------------------------------------------
['__main__',......]
['A', '_B', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__my__', '__name__', '__package__', '__spec__', 'sys']
1
#testb中的变量A,_B,__my__都被导入了

如上所示,可以看到使用from testb import *导入__all __列表中的名称(模块内的变量名)

总结

  • 使用from module import * 导入
    • 如果模块没有__all __,from module import * 只导入非下划线开头的该模块的变量名.
    • 如果模块有__all __,from module import * 只导入__all __列表中指定的名称,哪怕这个名词是下划线开头的,或者是子模块
    • from module import *方式导入,使用简单,但是其副作用是导入大量不需要使用的变量,甚至有可能造成名称的冲突。而__all __可以控制被导入模块在这种导入方式下能够提供的变量名称,就是为了阻止from module import *导入过多的模块变量,从而避免冲突。因此,编写模块时,应该尽量加入__all __.
  • 使用 from module import name1,name2导入
    • 这种方式的导入是明确的,哪怕是导入子模块,或者导入下划线开头的名称
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值