前言
在大量的代码设计中,我们不可能将所有代码都写在一个.py文件,所以有了包、模块,而为了代码可以重复利用(复用性),就有了类、函数的概念。类和函数在下次介绍。
python中的包
python中的包,对应到计算机中,可以理解为文件夹,但是文件加下必须有一个名为__init__.py的文件,若没有此文件,python则会认为其只是一个普通的文件夹。
打开pycharm,创建一个包,如下:
![214cfe6a2ca43316ea2d0d24e92ae088.png](https://i-blog.csdnimg.cn/blog_migrate/af9ec50ebabd04e8d0ccced55771ad4d.jpeg)
![f9cbfa1440809c03dd400edaf7855ea4.png](https://i-blog.csdnimg.cn/blog_migrate/0901d2b14dc2d088aec54f5871ee1426.jpeg)
python中的模块
python中的模块就非常好理解了,实际上,之前所有的.py文件,我们都可以称之为一个模块。单独的一个py文件就是一个模块。
![fa35fc55d4c539f77b82374bbbed9e5c.png](https://i-blog.csdnimg.cn/blog_migrate/f30f296bfcd2afdeb672944c66b1cf6a.jpeg)
![02739326336fa685c4d4906f22b156a6.png](https://i-blog.csdnimg.cn/blog_migrate/1d48f2409c3a5415c6634391834959d0.jpeg)
test1和test2不同区别就是test2是和package这个包是同级目录,而test1是属于package包的。
再来看下总的概念:
![9ac819ca53485dee64cbf4607bee2575.png](https://i-blog.csdnimg.cn/blog_migrate/435963b2b7f629657112abc7abae0706.jpeg)
包和模块的引入
1. 模块处于同级目录 ( 并且不在包下 )
当我们想在一个模块中使用另一个模块中的变量时,如何操作呢?test2、test3处于同一级目录。
![a1dd9137c83f0b51682df8dddb01ab88.png](https://i-blog.csdnimg.cn/blog_migrate/caa3f4748ad6a9b7cfd9185edadda960.jpeg)
我想在test3中引入test2的变量,test2.py中有个变量a = 2。
![794eb21d3a28d9f88da3ca8ae25fb4c7.png](https://i-blog.csdnimg.cn/blog_migrate/3ea934a23500599a0134645906b3d299.jpeg)
![da4b6f65c9ba0cc7e761b8ec83aa9a43.png](https://i-blog.csdnimg.cn/blog_migrate/dad4c72775d6f28a77411fe55b39d817.jpeg)
![b59bb9eb02044a794b15aef84990667d.png](https://i-blog.csdnimg.cn/blog_migrate/0818411cc684649dfe2035d29318fc56.jpeg)
如上所示,只需要在当前模块,用import语句,即可导入模块,具体使用的时候需要用模块的名字.变量。
import 后面必须是模块的名称! ------> import modul name
还有一种写法如下图pycharm中:
![c88850fa42955c58b899dd93a31a700e.png](https://i-blog.csdnimg.cn/blog_migrate/7b5bab5b8fefee58ca30be95bd310ba0.jpeg)
如上所示,只需要在当前模块, from 模块名字 import 变量
2. 模块处于同级目录 ( 在同一包下 )
来看下,test1,test4都属于package包下的模块。
![c196bf68a04179e9e9ff7e064fc6213f.png](https://i-blog.csdnimg.cn/blog_migrate/6ee8a28802f76ed7fa459aa0ab4077bc.jpeg)
test1.py中有着字符串a = 'I am success!'
![12ed9378a0d9230d430ea179790910b3.png](https://i-blog.csdnimg.cn/blog_migrate/eeb347acf8aefd8bc5c2dec576ff9456.jpeg)
在test4.py中引用test1.py中的a,如何引用呢?
可以看到如下:
![efe8bb05b368819fdad1875fa36da332.png](https://i-blog.csdnimg.cn/blog_migrate/8e588ffe651d00c64a8c2652fbe27c3e.jpeg)
关键语法:import 包名.模块名 as 别名
但是!!!!!!!如果我们脱离pycharm,找到本机相应的python目录,通过cmd来运行下,看下效果如何:
![1cfaa951146104f382f8cd5f859ed089.png](https://i-blog.csdnimg.cn/blog_migrate/1192f5d9c7be3dd618966d1cf3d6979f.jpeg)
![bb74b5a70fb99851d05041f6c49ed9b5.png](https://i-blog.csdnimg.cn/blog_migrate/8ffd76f0a2cef6d81e4a1d4c45fa0b24.jpeg)
可以清晰的看到上图,通过命令行模式执行就会报错!错误显示模块没有被找到:没有模块叫'package'。这是为什么呢?在pycharm中通过右键run as运行test4,可以看到控制台成功输出,而本地调用命令行的形式就报错了!
打开pycharm的setting,搜索 python console,右侧其中有一项,add content roots to pythonpath,默认pycharm是勾选上此项的。此项的意思是将内容的根路径加到python的环境变量路径下。
![8caa67067f5abeb5fc36f25cd63ccc28.png](https://i-blog.csdnimg.cn/blog_migrate/f50ce313a7ac8059a7e4558091cf0ff0.jpeg)
可以看到上图下面代码块里写着一堆代码,正是这段代码,我们才可以在pycharm中正确运行。
我们可以在test1.py里来看下sys.path,顺便打印看下结果。
![da9d55939a332b7049231dac7b872860.png](https://i-blog.csdnimg.cn/blog_migrate/2b65d7fc310de3906389def739fbe3a7.jpeg)
pycharm控制台输出:
['F:pycharmpython14package', 'F:pycharmpython14', 'D:python3.6python36.zip', 'D:python3.6DLLs', 'D:python3.6lib', 'D:python3.6', 'C:甥敳獲syAppDataRoamingPythonPython36site-packages', 'D:python3.6libsite-packages', 'D:python3.6libsite-packageswin32', 'D:python3.6libsite-packageswin32lib','D:python3.6libsite-packagesPythonwin']
实际通过命令行输出,应该没有'F:pycharmpython14' 这一项,因为这一项是pycharm中setting自动加上的!
实际控制台输出:
['F:pycharmpython14package','D:python3.6python36.zip', 'D:python3.6DLLs', 'D:python3.6lib', 'D:python3.6', 'C:甥敳獲syAppDataRoamingPythonPython36site-packages', 'D:python3.6libsite-packages', 'D:python3.6libsite-packageswin32', 'D:python3.6libsite-packageswin32lib','D:python3.6libsite-packagesPythonwin']
sys.path是一个list。默然情况下python导入文件或者模块的话,他会先在sys.path里找模块的路径。如果没有的话,程序就会报错。可以看到,sys路径下有package的包名,而没有test4.py中引用test1.py模块。
而pycharm能够成功运行,正是因为它已经帮我们把项目的根路径添加到了python的环境变量中。所以我们仿照其类似写法也可以完成!
解决方案:
这里不得不说几个重要的python自带模块了,如下:
①
__file__ : python模块自身的名称 pycharm打印下__file__:
可以看到pycharm会将模块的绝对路径输出到控制台上。
![ae40ab05e2ed997ec7e507a587db031a.png](https://i-blog.csdnimg.cn/blog_migrate/9266f0cc1b5c19741b9c24f0ebe1382b.jpeg)
在用命令行执行下看看:
![6e62dee7ef93d48b6d1dcb3c2a49313d.png](https://i-blog.csdnimg.cn/blog_migrate/cddebf7b37c5c6606207c3d255ee4f2a.jpeg)
python额外小知识:可以看到上图有一个__pycache__的文件夹,这个文件夹在pycharm的目录中,我们是看不到的,那么此文件夹的意义何在呢?点进去看下:
![ca9168fa058eb512a8ba4361153eff6d.png](https://i-blog.csdnimg.cn/blog_migrate/ce97970939276b4c46d05fc76cac88f6.jpeg)
继续回归正题:
②
import sys,os : sys ,os模块是python系统自带模块os模块: operate system 操作系统的意思,一般可以通过调用此模块来对系统进行相关操作sys 模块: system 系统的意思,通过此模块来实现对python自定义包和模块的导入
有了以上两个知识点,我们可以对test4.py进行如下操作:
import sys,osprint(__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:
![20f5655ddbe2116ceb11ba00b6f9136a.png](https://i-blog.csdnimg.cn/blog_migrate/a98e0504576a5cf6268531e8387dab07.jpeg)
可以看到上图结果:
__file__ 模块名字test4.py os.path.abspath(__file__) 模块名字的绝对路径F:pycharmpython14packageest4.pyos.path.dirname(os.path.abspath(__file__)) 模块的包名绝对路径F:pycharmpython14packageos.path.dirname(os.path.dirname(os.path.abspath(__file__)))F:pycharmpython14 项目本身的绝对路径
通过最后一步,我们可以将项目本身的路径直接拼入python的sys下
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(base_path)
验证究竟有没有加到我们的python环境变量中,最终代码为:
import sys, osprint(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)
通过命令行执行来看下:
![d591d9b6bfeadb00d504b5bbbbd85deb.png](https://i-blog.csdnimg.cn/blog_migrate/2dfcc4b19449008be327e122b6746edd.jpeg)
有了以上的所有操作步骤,我们可以完美的将test1.py的a变量引入test4.py中了!来看下命令执行:
import sys, osbase_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)
![0c772bb55e971cbb7b29438d8445da8e.png](https://i-blog.csdnimg.cn/blog_migrate/57da13a4a7c9acb7fd9fcc210adabbdd.jpeg)
成功!
写到这里涉及的知识点就已经这么多了。。。继续写。。。
3. 包处于同级目录 ( 包和包同级,包1下的模块引入包2下的模块变量 )
![8649e5b555ac45ca9390d9b57e9fb72b.png](https://i-blog.csdnimg.cn/blog_migrate/00f2c1f71e891b6ff3d3eaf99ff8bed4.jpeg)
可以看到,通过from test3 import c,pycharm中是正常输出的,控制台是报错的!原因实际和“2.模块处于同级目录(在同一包下)”的解释是一样的,只需要在引入自定义包之前,将我们项目的根路径加到python的系统变量中即可。
4. 模块处于不同级目录 ( 包和模块同级,模块引入包下模块的变量 )
![5f48fffdf3a3ecfa9d9a3dae68d9fdd8.png](https://i-blog.csdnimg.cn/blog_migrate/a7c8e431add689ca2a851e6cadf35475.jpeg)
![361e06724a083be63d9ddf959518ed3c.png](https://i-blog.csdnimg.cn/blog_migrate/9921ade3aad318dfc3b91ea928bec001.jpeg)
![b8b2d7f831585011554df23070f07b8b.png](https://i-blog.csdnimg.cn/blog_migrate/4c09edd1c9f093ca3b380812d984589d.jpeg)
若属于3的情况,可以看到,不需要对python系统进行sys.append,可以正常使用import 或者 from 语句进行导入。
5. 模块处于不同级目录 ( 包和模块同级,包下模块引入与包模块同级的变量 )
test3.py中有: c = 123455666在packeage下的test1.py调用:
![0e8ca29fdcc3c4878ba2516bf1d69832.png](https://i-blog.csdnimg.cn/blog_migrate/dc65a605ab72ccf4715d7c53f309977f.jpeg)
可以看到,通过from test3 import c,pycharm中是正常输出的,控制台是报错的!原因实际和“2.模块处于同级目录(在同一包下)”的解释是一样的,只需要在引入自定义包之前,将我们项目的根路径加到python的系统变量中即可。
import sys, osbase_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(base_path)from test3 import cprint(c)
![b408347cec3369cee5a0e7595d9c67cb.png](https://i-blog.csdnimg.cn/blog_migrate/0a109588f8f0ae16060735536c39e2a4.jpeg)
模块之前的相对引入
什么叫相对引入呢?相对路径大家可能听说过,相对引入和相对路径是一个道理的,比如 .代表的是当前目录,..代表的是上级目录,此处的写法就是相对路径,相对于某个文件来说,即相对!
实际上,在2.模块处于同级目录(在同一包下)中,还有一种相对引入的写法,但是对于test4.py引入test1.py来说,不能直接运行test4.py,否则会报错。来看下:
![5773e932c5a2a565f94990c2d7173564.png](https://i-blog.csdnimg.cn/blog_migrate/33e9a71207d34833ec7787283179a884.jpeg)
test1.py中有个a字符串:
test1.pya = 'I am success !'
test4.py中,我用from .test1 import a来引入test1.py的变量a,注意,包下同级目录,我使用的是.test1 !!!!
test4.pyfrom .test1 import ab = a + 'I am test4.py import .test1'
如果此时我直接将test4.py运行,并且打印b,就会报错!
![b41b3dbf79cad7bd2be1d6aa57be9cea.png](https://i-blog.csdnimg.cn/blog_migrate/00909ba03b765374876fb098c1c4c7ff.jpeg)
ModuleNotFoundError: No module named '__main__.test1'; '__main__' is not a package
如果此时,我通过test2.py间接行调用test4.py中的b
from package.test4 import bprint(b)
无论是pycharm还是命令行,都是有成功运行的:
![04f32839d49a58d8bb8e152454e64aec.png](https://i-blog.csdnimg.cn/blog_migrate/7651c8ca58e34d78532e2890015dad40.jpeg)
也就是说python对于相对引入来说,主动引入的函数不能作为主体去运行!
pycharm中可能会遇到的import报错
有人可能会遇到,当一个新项目导入到pycharm中,python代码的import有可能会报错,可以将项目设置为根路径,这样import错误即可消失,操作如下:
![99a3c5b27cfbf1626c4e6877323c3994.png](https://i-blog.csdnimg.cn/blog_migrate/713c99e9dd0b31d8480ced7c7ce1ba3e.jpeg)
包和模块自身的额外小知识点
- 关于包下的 init.py
init,中文意思是初始化的意思,而__init__.py实际上就是作为包名来配合的,当我们调用一个包时,第一步python就会去调用__init__.py模块,所以,经常我们可以将包下的__init__.py中放入一些需要初始化的操作。
举个例子:
![4b6820d5db921514e1654827996432ad.png](https://i-blog.csdnimg.cn/blog_migrate/24b5858d019f4482cc7dc00ab5dc5a98.jpeg)
__init__.py:init_a = 'I am __init__.py'print(init_a)
在package包下定义了初始化的字符串。 而test2.py调用package下的test1.py中的a变量时:
test2.py:from package.test1 import aprint(a)test1.py:a = 'I am success !'
可以看到下图运行结果,先输出了初始化模块中的字符串:
![f39d553e37b55a4d1ad7b4a01bcebdfa.png](https://i-blog.csdnimg.cn/blog_migrate/50f47a2092c3724afde5b2c0323fa223.jpeg)
- 关于模块中的限定变量写法
依然是test2.py引入test1.py的变量:
![b3951c8724a0f4e6c72114279369f931.png](https://i-blog.csdnimg.cn/blog_migrate/e7cab9cd0f5bba1a0a9b8567e2be44c2.jpeg)
test2.py:from package.test1 import a,b,cprint(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单独引入三个变量,运行结果:
![45ac6a701a977eeff0242af9f63e72cc.png](https://i-blog.csdnimg.cn/blog_migrate/0abf4622f45c327ea187fcfb9aea4308.jpeg)
若将import 后面改成* ,则会限制变量。
![1778a35bedf4e53e01fc7499b115a5dd.png](https://i-blog.csdnimg.cn/blog_migrate/0d0bfeff7daeb076bdfbe462ed88894d.jpeg)
而此处所说,就是因为在test1.py中有着__all__ = [] ,这样的写法可以限定住import * 的限制,test4.pyimport *时,则会被限制住骂人的语句!
import 模块的万金油方法
上面说了这么多种情况,如果你实在是记不住,那么请记住一点,万金油的import方式,就是在你所有模块的入口模块处,以下面代码为例,将你项目本身的绝对路径拼入到python 的系统path下, 这样自定义的包一定不会出错!!!
import sys, osbase_path = os.path.dirname(os.path.dirname( os.path.abspath(__file__)))sys.path.append(base_path)
有想学python的同学,欢迎关注公号:migezatan.(咪哥杂谈)