Python正课50 —— 包

本文内容皆为作者原创,如需转载,请注明出处:https://www.cnblogs.com/xuexianqi/p/12593471.html

一:什么是包

包就是一个含有___init__.py的文件夹
在导包的时候,导入的其实__init__.py文件
包的本质其实模块的一种形式

二:为何要有包

包的本质是模块的一种形式,包是用来被当做模块导入

1.产生一个名称空间

2.运行包下的__init__.py文件,将运行过程中产生的名字都丢到1的名称空间中

3.在当前执行文件的名称空间

1.在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2.创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模

三:包的使用

1.导入包与___init___.py

1.首次导入会运行包内__init__文件内的代码
2.产生__init__文件的名称空间,将运行__init__文件时产生的名字都求导该名称空间中
3.在执行文件中得到一个全局名称----包的名字(bag),该名字指向__init__.py文件的名称空间
import new
print(new.x)  # 会去找new包下的__init__.py,相当于print(__init__.x)
from new import x
print(x)

2.一个python文件有两种用途

① 被当成程序运行

为了区别同一个文件的不同用途,每个py文件都内置了__name__变量,该变量在py文件被当做脚本执行时赋值为“__main__”,在py文件被当做模块导入时赋值为模块名

② 被当做模块导入

作为模块foo.py的开发者,可以在文件末尾基于__name__在不同应用场景下值的不同来控制文件执行不同的逻辑

3.二者的区是什么?

① 作为程序运行

  直接右键运行该Python文件

② 作为模块导入

  作为模块,被import导入到其他文件中

四:导入模块/包的2种方式

方式一:import + 模块名

优点:该模块内的名字不会和当前名称空间的名字冲突

缺点:在使用这个模块下的功能或者名字的时候需要加前缀显得麻烦

# impot导入模块在使用时必须加前缀"模块."

1、产一个模块的名称空间
2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
3、在当前名称空间拿到一个名字,该名字与模块名称空间中的某一个内存地址
from foo import x # x=模块foo中值0的内存地址
from foo import get
from foo import change

方式二:from + 模块 import 名字(模块中的函数名或者变量名或者*(全部导入))

优点:代码精简,使用模块中功能不需要加前缀

缺点:容易和当前名称空间的名字混淆

# from foo import x   # x = 模块foo中 值1 的内存地址
# x = 1111

# 一行导入多个名字(不推荐使用)
# from foo import x,get,change

# *:导入模块中的所有名字(不推荐使用)
# from foo import *
# print(x)
# print(get)
# print(change)

# 了解:__all__
# from foo import *
# print(x)
# print(get)
# print(change)
# __all__ = [] 可以控制*

# 起别名
# from foo import get as g
# print(g)

五:绝对导入与相对导入

绝对导入,以包的文件夹作为起始来进行导入

from bag.this import x	# 导入在bag包下this.py文件夹中的变量x

print(x)

相对导入:仅限于包内使用,不能跨出包(包内模块之间的的导入,推荐使用相对导入)

# .:表示当前文件夹
# ..:表示上一层文件夹
# 局限性:.不能超出foo之外
# 注意:相对导入仅限于包内使用,不能跨出包,否则会出现语法错误
# 包内的相互导入推荐使用相对导入

from .this import # 导入在当前包内的this.py文件夹中的变量x

print(x)

两种导入方式对比

两种导入模式的优缺点:

绝对导入:(类似于绝对路径)
以顶级的包为起始,点的形式往下找子包,一定能找到
更改包名或着模块名的时候,导入的方式全部要改变
能够导入任意地方的包

相对导入:(类似于相对路径)
包内模块彼此之间的导入,推荐使用相对导入
当对包名更改时,因为只考虑在包内的相对位置
不能跨出包

六:模块的搜索路径优先级

无论是import还是from...import在导入模块时都涉及到查找问题

# 优先级:
# 1、内存(内置模块)
# 2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块
# import sys
# 值为一个列表,存放了一系列的对文件夹
# 其中第一个文件夹是当前执行文件所在的文件夹
# print(sys.path)
# import foo # 内存中已经有foo了
# foo.say()
#
# import time
# time.sleep(10)
#
# import foo
# foo.say()

了解:sys.modules查看已经加载到内存中的模块

import sys
import foo  # foo = 模块的内存地址
del foo

print(sys.modules)

七:循环导入

循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块
而在另外一个模块中又返回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常

m1.py

print('正在导入m1')
from m2 import y

x='m1'

m2.py

print('正在导入m2')
from m1 import x

y='m2'

run.py

import m1

输出:

正在导入m1
正在导入m2

ImportError: cannot import name 'x' from partially initialized module 'm1' (most likely due to a circular import) (E:Python学习相关正课第4周周5 day21Teacherm1.py)

解决方法:

方案一:导入语句放到最后,保证在导入时,所有名字都已经加载过
方案二:导入语句放到函数中,只有在调用函数时才会执行其内部代码
原文地址:https://www.cnblogs.com/xuexianqi/p/12593471.html