python导入模块的本质,关于python导入模块和package的一些深度思考

背景

在python中有导入模块和导入package一说,这篇文章主要介绍导入模块和package的一些思考。

首先什么是模块?什么是package?

模块:用来从逻辑上组织python代码(变量,函数,类),本质上就是以.py结尾的python文件

package:本质上就是一个目录,但是必须带一个init.py的文件,它是用来从逻辑上组织模块的

import的本质是什么?

导入模块的本质:就是把python文件拿来解释一遍

导入包的本质:就是执行该package下的init.py文件、

深入思考

导入模块

如果我现在有一个这样的目录:

d290fce51b98

文件目录结构

在bin文件目录下的hello.py内容是:

def hello():

print('i am in bin dir')

在Day5文件目录下的hello.py内容是:

def hello():

print('i am in Day5 dir')

在pythonFile文件目录下的hello.py内容是:

def hello():

print('i am in pythonFile dir')

如果我现在在bin目录下的test.py下写入

import hello

hello.hello()

会出现的结果是什么呢?

大家很自然会想到是

i am in bin dir

是的确实是这样的。但是为什么呢?

这个需要提及到环境变量的问题,我们可以看看当前文件所处的环境变量到底里面有什么?

使用下面的语句:

import sys, os

print('--------')

for path in sys.path:

print(path)

print('--------')

其中sys.path是所有环境变量的所构成的列表,我们将里面的内容分行打印。可以得到:

--------

D:\0 sty file\myCode\pythonFile\Day5\bin

D:\0 sty file\myCode\pythonFile

C:\ProgramData\Anaconda3\python36.zip

C:\ProgramData\Anaconda3\DLLs

C:\ProgramData\Anaconda3\lib

C:\ProgramData\Anaconda3

C:\ProgramData\Anaconda3\lib\site-packages

C:\ProgramData\Anaconda3\lib\site-packages\Babel-2.5.0-py3.6.egg

C:\ProgramData\Anaconda3\lib\site-packages\win32

C:\ProgramData\Anaconda3\lib\site-packages\win32\lib

C:\ProgramData\Anaconda3\lib\site-packages\Pythonwin

--------

这是我电脑里面的当前文件运行时候的环境变量。我们可以知道导入模块和package时候,我们的程序会从这个sys.path中从前到后寻找这些目录下有没有我们要找的模块,可以看见D:\0 sty file\myCode\pythonFile\Day5\bin是在第一个的所有我们直接导入hello模块。python找到的D:\0 sty file\myCode\pythonFile\Day5\bin里面的hello.py找到之后,就不找了,然后打印出来了。

导入的问题来了

现在问题来了,我现在就想要导入D:\0 sty file\myCode\pythonFile\Day5下面的hello,那我应该怎么办?

我们知道在python中我们可以找到当前文件所在目录的父目录,然后将他加入到运行环境时候的环境变量中去,注意是运行环境中的,因为在当前python文件运行结束后,这个环境变量就释放了。

我们可以了解如下语句:

import sys, os # 导入系统模块

print(os.path.abspath(__file__)) #打印当前文件所处的绝对路径

print(os.path.dirname(os.path.abspath(__file__))) #打印当前文件所处的目录

# 打印当前文件所处的目录的父目录

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

# Outputs:

# D:\0 sty file\myCode\pythonFile\Day5\bin\test.py

# D:\0 sty file\myCode\pythonFile\Day5\bin

# D:\0 sty file\myCode\pythonFile\Day5

然后我们就可以在写下如下的代码:

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

sys.path.append(BASE_DIR) # 将BASE_DIR加入到系统环境变量

我们将当前文件所在目录的父目录加入到环境变量中去,然后我们在打印下sys.path得到:

--------

D:\0 sty file\myCode\pythonFile\Day5\bin

D:\0 sty file\myCode\pythonFile

C:\ProgramData\Anaconda3\python36.zip

C:\ProgramData\Anaconda3\DLLs

C:\ProgramData\Anaconda3\lib

C:\ProgramData\Anaconda3

C:\ProgramData\Anaconda3\lib\site-packages

C:\ProgramData\Anaconda3\lib\site-packages\Babel-2.5.0-py3.6.egg

C:\ProgramData\Anaconda3\lib\site-packages\win32

C:\ProgramData\Anaconda3\lib\site-packages\win32\lib

C:\ProgramData\Anaconda3\lib\site-packages\Pythonwin

D:\0 sty file\myCode\pythonFile\Day5

--------

我们可以看出D:\0 sty file\myCode\pythonFile\Day5加到了sys.path的最后一个,现在我们将之前的开头的写的

import hello

hello.hello()

一定要注释,一定要注释,一定要注释,因为如果不去掉的话,这个hello.hello()方法就已经存放在内存里面了,不管你后面如何去该环境变量,python会始终去找到内存中直接有的hello()方法。

我们将这行代码加到test.py的最后面,运行得到结果是:

i am in bin dir

这是为什么呢,原因还是那个sys.path中个路径顺序的问题,如果我们要让我们设置的BASE_DIR 中的模块首先导入我们就需要用列表中的insert()方法2而不是‘append()’的了,这就避免了再环境变量中已经有的路径有同名的模块。

我们改为:

sys.path.insert(0, BASE_DIR)

发现输出的结果就是

i am in Day5 dir

完整代码如下:

# import hello #使用添加环境变量后的模块一定要注释到

# hello.hello()

import sys, os

print('--------')

for path in sys.path:

print(path)

print('--------')

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

#sys.path.append(BASE_DIR)

sys.path.insert(0, BASE_DIR)

print('--------')

for path in sys.path:

print(path)

print('--------')

import hello

hello.hello()

最后提一下:

如果我们要使用pythonFile下的hello中hello(),道理还是一样的,大家自己去实现吧。

导入package

导入package时候设置环境变量的问题和导入模块是一样的,就不赘述了,但是需要注意的一点是导入package后,package下的init.py里的内容是自动执行的。

如我在test_package下的init.py中写入

print('i am in test_package __init__')

当我们在

import test_package

后就自动执行了,这在我们管理很多文件时候,进行初始化的作用相当好用啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值