Python入门系列15 - 史上最详细的包和模块import讲解篇

小黄用python

共 6818字,需浏览 14分钟

 ·

2019-08-29 09:07

Python入门系列15

dcab4e86f4a8dbaf1ea9fdaa6212e53d.webp

史上最详细的包和模块import讲解篇


本篇文字图片较多,阅读时间不详,能否读完,纯看你有没有学习的心了!!!


1

前言


在大量的代码设计中,我们不可能将所有代码都写在一个.py文件,所以有了包、模块,而为了代码可以重复利用(复用性),就有了类、函数的概念。类和函数在下次介绍。


2

python中的包


python中的包,对应到计算机中,可以理解为文件夹,但是文件夹下必须有一个名为__init__.py的文件,若没有此文件,python则会认为其只是一个普通的文件夹。

打开pycharm,创建一个包,如下:

bbe1cec32ce85bd2238227479a23bf79.webp

cb6e0e27ca14e7093631bb8b15adbb22.webp


3

python中的模块


python中的模块就非常好理解了,实际上,之前所有的.py文件,我们都可以称之为一个模块。单独的一个py文件就是一个模块。

3a8905d23a76ab3722d88e789558d70f.webp

6b2b7eb9f7bca27262057a1b759fdeec.webp

test1和test2不同区别就是test2是和package这个包是同级目录,而test1是属于package包的。


再来看下总的概念:

3c021b8dc2c780d974f9efb938acea2a.webp


4

包和模块的引入


1.模块处于同级目录(并且不在包下

当我们想在一个模块中使用另一个模块中的变量时,如何操作呢?test2、test3处于同一级目录。

6a828cda3096e5bb680ce6f8226c29c2.webp


我想在test3中引入test2的变量,test2.py中有个变量a = 2。

30c83441e80d0848bad604876ead733a.webp

f0a86a66590ca5b99ec0b6edcb653743.webp

dc0eb072af8c0d526f8f90798f1a79c1.webp


如上所示,只需要在当前模块,用import语句,即可导入模块,具体使用的时候需要用模块的名字.变量。

import 后面必须是模块的名称!------> import modul name


还有一种写法如下图pycharm中:

adc73a0ee3d015aa6a0c909ab02790d0.webp

如上所示,只需要在当前模块,     from 模块名字 import  变量     


2.模块处于同级目录(在同一包下

来看下,test1,test4都属于package包下的模块。

8b5a2f8d6c430112be0b9615116b3991.webp


test1.py中有着字符串a = 'I am success!'

9b6fd1302b01ce67804b698e43b12e68.webp


在test4.py中引用test1.py中的a,如何引用呢?

可以看到如下:

bca7594b632522df941b9b6db1af4007.webp


关键语法:import 包名.模块名 as 别名


但是!!!!!!!如果我们脱离pycharm,找到本机相应的python目录,通过cmd来运行下,看下效果如何:


994492240b38d0e7f34b3db326ab6eeb.webp

8eed6b41a14bd15fee03ee10bd0d2fe2.webp


可以清晰的看到上图,通过命令行模式执行就会报错!错误显示模块没有被找到:没有模块叫'package'。这是为什么呢?在pycharm中通过右键run as运行test4,可以看到控制台成功输出,而本地调用命令行的形式就报错了!


打开pycharm的setting,搜索 python console,右侧其中有一项,add content roots to pythonpath,默认pycharm是勾选上此项的。此项的意思是将内容的根路径加到python的环境变量路径下。

a16ac65d8d2b3b9d4ec570a39922964d.webp

可以看到上图下面代码块里写着一堆代码,正是这段代码,我们才可以在pycharm中正确运行。


我们可以在test1.py里来看下sys.path,顺便打印看下结果。

8bfb88bb971015c09339a6f1c7a1eeb3.webp


pycharm控制台输出:

['F:\\pycharm\\python14\\package''F:\\pycharm\\python14'
'D:\\python3.6\\python36.zip'
'D:\\python3.6\\DLLs''D:\\python3.6\\lib''D:\\python3.6'
'C:\\Users\\sy\\AppData\\Roaming\\Python\\Python36\\site-packages'
'D:\\python3.6\\lib\\site-packages'
'D:\\python3.6\\lib\\site-packages\\win32'
'D:\\python3.6\\lib\\site-packages\\win32\\lib',
 'D:\\python3.6\\lib\\site-packages\\Pythonwin']

实际通过命令行输出,应该没有'F:\\pycharm\\python14' 这一项,因为这一项是pycharm中setting自动加上的!

实际控制台输出:

['F:\\pycharm\\python14\\package',
'D:\\python3.6\\python36.zip'
'D:\\python3.6\\DLLs''D:\\python3.6\\lib''D:\\python3.6'
'C:\\Users\\sy\\AppData\\Roaming\\Python\\Python36\\site-packages'
'D:\\python3.6\\lib\\site-packages'
'D:\\python3.6\\lib\\site-packages\\win32'
'D:\\python3.6\\lib\\site-packages\\win32\\lib',
 'D:\\python3.6\\lib\\site-packages\\Pythonwin']


sys.path是一个list。默认情况下python导入文件或者模块的话,他会先在sys.path里找模块的路径。如果没有的话,程序就会报错。可以看到,sys路径下有package的包名,而没有test4.py中引用test1.py模块。


而pycharm能够成功运行,正是因为它已经帮我们把项目的根路径添加到了python的环境变量中。所以我们仿照其类似写法也可以完成!


解决方案:

这里不得不说几个重要的python自带模块了,如下:

① 

__file__   : python模块自身的名称

pycharm打印下__file__:

可以看到pycharm会将模块的绝对路径输出到控制台上。

ab8849639bb898458f84338a7bff0fca.webp


在用命令行执行下看看:

b6d187f32d19e958f27fa92d4f95b45e.webp


python额外小知识:可以看到上图有一个__pycache__的文件夹,这个文件夹在pycharm的目录中,我们是看不到的,那么此文件夹的意义何在呢?点进去看下:

e9f1d2524feaa7463181aacc77353c5b.webp

Python程序运行时不需要编译成二进制代码,而直接从源码运行程序,简单来说是,Python解释器将源码转换为字节码,然后再由解释器来执行这些字节码。而解释器的具体工作: 

1、完成模块的加载和链接。

2、将源代码编译为PyCodeObject对象(即字节码),写入内存中,供CPU读取。

3、从内存中读取并执行,结束后将PyCodeObject写回硬盘当中,也就是复制到.pyc或.pyo文件中,以保存当前目录下所有脚本的字节码文件。

4、若再次执行该脚本,它先检查【本地是否有上述字节码文件】和【该字节码文件的修改时间是否在其源文件之后】,是就直接执行,否则重复上述步骤。

第一次执行代码的时候,Python解释器已经把编译的字节码放在__pycache__文件夹中,这样以后再次运行的话,如果被调用的模块未发生改变,那就直接跳过编译这一步,直接去__pycache__文件夹中去运行相关的 *.pyc 文件,大大缩短了项目运行前的准备时间。


CSDN来源:


https://blog.csdn.net/index20001/article/details/73501375



继续回归正题:


import sys,os   :  sys ,os模块是python系统自带模块

os模块:operate system 操作系统的意思,一般可以通过调用此模块来对系统进行相关操作

sys 模块:system 系统的意思,通过此模块来实现对python自定义包和模块的导入


有了以上两个知识点,我们可以对test4.py进行如下操作:

import sys,os

print(__file__)
print(os.path.abspath(__file__))
print(os.path.dirname(os.path.abspath(__file__)))
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


因为pycharm会对__file__进行路径补充,所以我们用命令行来执行test4.py:

9ae0a12672be2a96b844ca3cb8017023.webp


可以看到上图结果:

__file__             模块名字
test4.py           
os.path.abspath(__file__)     模块名字的绝对路径
F:\pycharm\python14\package\test4.py
os.path.dirname(os.path.abspath(__file__))    模块的包名绝对路径
F:\pycharm\python14\package


os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
F:\pycharm\python14                           项目本身的绝对路径


通过最后一步,我们可以将项目本身的路径直接拼入python的sys下

base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)


验证究竟有没有加到我们的python环境变量中,最终代码为:

import sys, os

print(sys.path)
print(__file__)
print(os.path.abspath(__file__))
print(os.path.dirname(os.path.abspath(__file__)))
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)
print(sys.path)


通过命令行执行来看下:

04d3b8ba60f7dee78f7e4f54f7b5a7ce.webp


有了以上的所有操作步骤,我们可以完美的将test1.py的a变量引入test4.py中了!来看下命令执行:


import sys, os
base_path = os.path.dirname(os.path.dirname(
                            os.path.abspath(__file__)))
sys.path.append(base_path)
----------------  sys拼接 一定要在自定义包引入之前定义   ----------------------------------
import package.test1 as test1       注意import的顺序。
print(test1.a)


78af755c7ce1e444cc69e7db7f63a804.webp

成功!

写到这里涉及的知识点就已经这么多了。。。继续写。。。


3.包处于同级目录(包和包同级,包1下的模块引入包2下的模块变量

0f70427182547d5cf6431f09c62ba460.webp

可以看到,通过from test3 import c,pycharm中是正常输出的,控制台是报错的!原因实际和“2.模块处于同级目录(在同一包下”的解释是一样的,只需要在引入自定义包之前,将我们项目的根路径加到python的系统变量中即可。


4.模块处于不同级目录(包和模块同级,模块引入包下模块的变量

c1446a26fb148ec3c36163ae4c2af8ed.webp

ecf69b994383990e34f825d27e1ccd29.webp

c69cf74c3a7215b0c8309abdcc555c53.webp

若属于3的情况,可以看到,不需要对python系统进行sys.append,可以正常使用import 或者 from 语句进行导入。


5.模块处于不同级目录(包和模块同级,包下模块引入与包模块同级的变量

test3.py 中有:

c = 123455666

在packeage下的test1.py调用:

fcc1155aa9cb09159d1c9777a1ee6ddb.webp


可以看到,通过from test3 import c,pycharm中是正常输出的,控制台是报错的!原因实际和“2.模块处于同级目录(在同一包下)”的解释是一样的,只需要在引入自定义包之前,将我们项目的根路径加到python的系统变量中即可。


import sys, os
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)
from test3 import c
print(c)


c404989161b3586bfe5573a68df9fd5e.webp


5

模块之前的相对引入


什么叫相对引入呢?相对路径大家可能听说过,相对引入和相对路径是一个道理的,比如 .代表的是当前目录,..代表的是上级目录,此处的写法就是相对路径,相对于某个文件来说,即相对!


实际上,在2.模块处于同级目录(在同一包下)中,还有一种相对引入的写法,但是对于test4.py引入test1.py来说,不能直接运行test4.py,否则会报错。来看下:

dfa9f2926f1c76476c3d5b07f94a8411.webp


test1.py中有个a字符串:

test1.py
a = 'I am success !'


test4.py中,我用from .test1 import a来引入test1.py的变量a,注意,包下同级目录,我使用的是.test1  !!!!

test4.py

from .test1 import a
b = a + 'I am test4.py import .test1'


如果此时我直接将test4.py运行,并且打印b,就会报错!

e9e2e3e14949eee4cfe3c434fd5c1c03.webp

ModuleNotFoundError: No module named '__main__.test1''__main__' is not 
a package


如果此时,我通过test2.py间接行调用test4.py中的b


from package.test4 import b
print(b)


无论是pycharm还是命令行,都是有成功运行的:

8fe5e287432d940e1aa3c7aa3c02fa9c.webp

也就是说python对于相对引入来说,主动引入的函数不能作为主体去运行!


6

pycharm中可能会遇到的import报错


有人可能会遇到,当一个新项目导入到pycharm中,python代码的import有可能会报错,可以将项目设置为根路径,这样import错误即可消失,操作如下:

0e8f8a3fbcd75b47fab1d412102df52f.webp


7

包和模块自身的额外小知识点


1. 关于包下的 __init__.py

init,中文意思是初始化的意思,而__init__.py实际上就是作为包名来配合的,当我们调用一个包时,第一步python就会去调用__init__.py模块,所以,经常我们可以将包下的__init__.py中放入一些需要初始化的操作。

举个例子:

e28546b737991b0bb46b723f8801dfb5.webp

__init__.py:
init_a = 'I am __init__.py'
print(init_a)

在package包下定义了初始化的字符串。


而test2.py调用package下的test1.py中的a变量时:

test2.py:
from
package.test1 import a
print(a)
test1.py:
a = 'I am success !'


可以看到下图运行结果,先输出了初始化模块中的字符串:

14efed84d194954fe727289a41b3750d.webp


2. 关于模块中的限定变量写法


依然是test2.py引入test1.py的变量:

897d7a8a70814528b1e4c7c395db5825.webp

test2.py:
from
package.test1 import a,b,c
print(a)
print(b)
print(c)
test1.py:
__all__ = ['a','b']
a = 'I am success !'
b = 'I am fail !'
c = 'I am fuc***  you!!! !'

在test2中引入test1通过import单独引入三个变量,运行结果:

a90858fccc319958ea6aea042eb9dfc7.webp


若将import 后面改成* ,则会限制变量。

3f8b5548ee5e7a3c78aa27a30c582598.webp

而此处所说,就是因为在test1.py中有着__all__ = []  ,这样的写法可以限定住import * 的限制,test4.py import *时,则会被限制住骂人的语句!


8

import 模块的万金油方法


上面说了这么多种情况,如果你实在是记不住,那么请记住一点,万金油的import方式,就是在你所有模块的入口模块处,以下面代码为例,将你项目本身的绝对路径拼入到python 的系统path下,这样自定义的包一定不会出错!!!

import sys, os
base_path = os.path.dirname(os.path.dirname(
os.path.abspath(__file__)))
sys.path.append(base_path)




以上,就是史上最最最最最最,超超超超详细的python模块和包的引入详解!!!!!欢迎转载!!!欢迎爆文!!!!

浏览 148
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报