系统模块调用
说到模块调用,大家应该都对import
有个基本的了解,在项目里面非常常见的比如import time
,from selenium import webdriver
等,我们经常在python
中通过from...import...
或import...
的语法可以引用一些系统模块,把系统模块引入后就可以调用模块里面定义好的方法,例如:
from time import ctime
print ctime()
import time
print time.ctime()
上面两个写法的最终目的都是为了获取并打印当前时间,
方法一中通过引入time
模块,导入其下面的ctime
方法,实现对ctime()
方法的调用,因为用了from
,指定了所需调用下面具体的ctime
方法,在用的时候直接写方法名ctime()
就可以调用了,
方法二里面是直接引入了整个time
模块,在用的时候需要加入模块名再进行其下面方法的引用time.ctime()
。
自定义模块调用
我们在进行编码设计的时候,往往需要自定义一些模块,其他程序可以调用这些模块,那么方法和原理还是和上面的系统模块调用是差不多的,让我们来举个栗子:
先创建一个目录ModPython
,下面定义一个公共模块PublicA.py
,为了更好的理解,我都是写的简单的方法的栗子。
#PublicA.py
def PubA():
print "I'm PublicA in /ModPythonh/PublicA.py"
接下来,还是在这个目录下新建一个python程序A.py
去调用这个自定义的模块
#A.py
import PublicA
PublicA.PubA()
运行A.py
的结果如下:
I am def PubA_1 in /ModPythonh/PublicA.py
[Finished in 1.1s]
结果成功地打印了PublicA.py
里面的PubA()
方法,说明这次调用成功了~
让我们来看看刚刚这个目录结构,因为PublicA
和A
这两个脚本都是在ModPython
里面的,所以直接用import
引用进来就好了:
ModPython
------/ PublicA.py
------/ A.py
这个时候如果我们在ModPython
这个项目里新建一个文件夹B
,里面新建一个b1.py
和b2.py
两个文件,目录和具体内容如下:
ModPython
------/ PublicA.py
------/ A.py
------/ B
------/ b1.py
------/ b2.py
#b1.py
def b1_1():
print "I am def b1_1 in /ModPythonh/B/b1.py"
def b1_2():
print "I am def b1_2 in /ModPythonh/B/b1.py"
#b2.py
def b2_1():
print "I am def b2_1 in /ModPythonh/B/b2.py"
def b2_2():
print "I am def b2_2 in /ModPythonh/B/b2.py"
这个时候我们在A.py
中import b1
,然后b1.b1_1()
,试试能不能成功……
这个时候报错了:ImportError: No module named b1
,提示说没有b1
这个模块,为什么呢,因为b1
和执行程序A.py
不在一个目录下,所以查找不到,这个时候该怎么解决,下面,咳咳(敲黑板(o゚v゚)ノ)重点请看……
跨目录模块调用
继续用上面已经建好的目录,然后继续按下面的规则来点更复杂的,建好了我们再依次来说说不同情况的跨目录模块调用
ModPython
------/ A.py
------/ PublicA.py
------/ B
------/ b1.py
------/ b2.py
------/ C
------/ c.py
在ModPython
里面再建文件夹C
,里面新建一个c.py
文件,文件建好了,那我们就来具体分情况说说吧。
同级目录下子文件调用
在我们文件结构中,与A.py
同级的有PublicA.py
还有就是B
、C
目录了,那么对于A.py
来说,b1
、b2
、c
就是子文件了。
如果我们想要在A.py
里面调用b1
,需要怎么做呢?
如果直接进行import b1
,上面试过了会报错,找不到模块b1
,因为b1
和A
不再一个目录下。
那么我们就找到b1
的父级目录B
,B
和A.py
在一个目录下,将B
作为一个模块,b1
、b2
都作为模块里面的方法去调用,为了让系统知道B
是一个模块,我们需要在B
下面新建一个叫做__init__.py
的文件,内容可以为空,这个文件可以告诉python B
是一个可以调用的模块了。
建好后我们再到A.py
中来调用 执行一下:
from B import b1,b2
b1.b1_1()
b2.b2_2()
运行结果:
I am def b1_1 in /ModPythonh/B/b1.py
I am def b2_2 in /ModPythonh/B/b2.py
这样就没有问题啦,我们再来补充一下另外两种写法也是可以的:
#A.py
from B.b1 import *
b1_1()
#A.py
import B.b1
B.b1.b1_1()
上面的三种方法都是基于__init__.py
文件是空的时候,我个人比较喜欢第一种,但是问题来了,如果B
下面有很多的文件,我每次调用可能需要的是不同的方法,能不能在每次调用的时候直接写:
from B import *
b1.b1_1()
b2.b2_2()
我们可以试着执行一下,看看行不行,这个时候提示:NameError: name 'b1' is not defined
,如果想要在每次执行调用的时候直接引入B下面的所有模块,我们就需要在__init__.py
文件中加入引入:
#__init__.py
import b1,b2
这样就能够直接写import *
啦。
同级目录之间的跨模块调用
ModPython
------/ A.py
------/ PublicA.py
------/ B
------/ init.py
------/ b1.py
------/ b2.py
------/ C
------/ c.py
我们再来看这个目录结构,梳理一下,对于B
、C
来说他们是同级的,b1
和c
也是同级的,如果我们需要在c
里面调用b
该怎么做呢?如果像之前A.py
调用的那样,还是会出现这个眼熟的error:ImportError: No module named B
,导入的是B
模块,而B
和c.py
文件也不是在一个目录下的了,如果需要那样调用,那么就要先回到上级目录C
,再开始from B import b1
跳转目录这个操作,我们需要调用python
的sys
模块进行实现,具体实现方法如下:
# c.py
import sys
sys.path.append('..')
from B import b1
b1.b1_1()
用append()
方法进行追加,..
表示回到上一级目录中去。
再来看我们这个栗子,c.py
回到上一级就是C
这个目录了,对于C
来说,和B
就是同级目录,B
下面已经创建了__init__.py
文件,已经是个模块可以用来引入,这个时候from B import b1
就没有问题可以顺利调用啦。
了解到这里,关于python
跨目录调用自定义模块的问题基本就得以解决了,实在不行,还有一个万能的方法(偷笑(/▽\)):
万能调用方法
只要在被调用文件所属的文件夹下创建好__init__.py
文件,然后引入sys
模块,在用append
进行追加的时候直接写上需要调用文件的绝对路径。
比如上面,我们要调用B
里面的文件,只需要找到B
的绝对路径,假设是C:\Users\ModPython\B
,那append
就这么写:
sys.path.append('C:\\Users\\ModPython')
这样就不管什么情况,都可以找到啦~~~~
关于.pyc文件的一点理解
在上述的各种自定义模块调用的操作后,如果回到之前新建的目录再多看一眼,相信不难发现,多出了几个.pyc文件,比如上面的b1.pyc
、__init__.pyc
,为什么会生成这些pyc
文件,pyc
文件又是有什么作用呢,我查阅了点资料在此说一下我的理解。
首先,来看一下python
的运行和编译机制的几个步骤:
python
运行自然要依赖解释器,解释器会将python
源码转换为字节码,然后再执行转换好的字节码。
那么当我们在引入调用一些模块时……
模块加载的过程中,源码就被虚拟机(解释器)翻译成了PyCodeObject
对象(也就是字节码)
将PyCodeObject
写入了CPU,下次运行将直接从内存中进行读取指令并执行程序
执行结束后,根据执行的方式决定是否将执行的结果写回硬盘,也就是复制到.pyc文件中
当再次执行时,先检查是否有.pyc文件,有的话,再检查字节码文件与自身的修改时间是否一致,一致则直接运行.pyc文件,不一致或是没有字节码文件则从新执行前面三个 步骤。
所以,我们前面调用过的模块都有生成一个.pyc
文件。
从上面的步骤进行分析,就可以看出.pyc
文件相对与.py
文件来说,由于是执行过并写入内存空间的,所以加载速度会比.py
文件要快,可以加速程序的运行。
当然了,由于执行起来.pyc
和.py
是一样的,.py
是直接以源码的形式进行呈现,而.pyc只是字节码文件,在某种程度上来说,还可以防止代码被偷看,具有一定的隐藏效果……
虽然对于菜鸡我而言,估计也没人偷看我代码ㄟ( ▔, ▔ )ㄏ
————————————————
版权声明:本文为CSDN博主「我的猪很厉害的」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_32897143/article/details/79960432