Python学习(15)--包和模块
Python学习(15)--包和模块
1.模块
为了更好的组织代码,以及让用户更方便的调用所提供的内置函数,Python将相关代码封装到了模块中,那么什么是模块呢?其实就是我们平时编写Python代码时写的后缀为py的文件。比如,Python为我们提供的有关字符串处理的函数就封装在string这个模块中,对应到Python中的代码文件就是string.py。
Python为我们提供模块都在安装目录下的lib文件夹下,如下:
通过截图可以看到lib文件夹下的.py文件,这些文件都是Python提供的供我们调用的模块。当然用户也可以使用自己定义的模块,如下我在我的项目文件下编写了一个模块文件,operator.py,模块名为operator,模块为我们提供了4个运算函数,分别实现运算数的加减乘除操作,operator.py的代码如下:
- <span style="font-size:24px;">def add(x,y):
- return x+y
- def subtract(x,y):
- return x-y
- def mul(x,y):
- return x*y
- def divide(x,y):
- return x/y</span>
那么写好模块之后又如何使它呢?使用模块之前需要导入模块,导入模块方法为import 模块名。调用模块中的函数方法为:模块名.函数名。具体代码例子如下:
- <span style="font-size:24px;">import operator
- print(operator.add(2,3))</span>
打印结果如下:
如上先导入模块operator,之后再调用模块operator为我们提供的方法add(x,y)。
下面我们来对operator.py做一些修改。如下:
- <span style="font-size:24px;">def add(x,y):
- return x+y
- def subtract(x,y):
- return x-y
- def mul(x,y):
- return x*y
- def divide(x,y):
- return x/y
- print(mul(5,6))</span>
如上所示,我们在文件最后调用函数mul(x,y),并打印返回结果。然后我们再次调用operator模块,调用代码如下:
- <span style="font-size:24px;">import operator
- print(operator.add(2,3))</span>
先看下打印结果,如下:
可以看到和之前相同的调用operator模块的代码,打印结果却和之前不一样,先打印了30,才打印出调用模块时代码执行的结果。那么打印结果30是怎么来的呢?其实这是调用模块operator执行其中的代码导致的结果。之前我们修改了operator中的代码,在最后加了一句print(mul(5,6)),在调用operator执行了这段代码,于是打印出了30。怎么证明这个30就是因为调用operator模块打印出来的呢?下面我们直接调用operator模块,并不做其他操作,只是导入模块。如下:
- <span style="font-size:24px;">import operator</span>
打印结果如下:
我们只是导入operator模块就打印了30,从而以上的叙述得到证明。然而我们在调用模块时,有时候并不希望执行被调用模块中的代码,因为这最后得到的结果可能会干扰我们对主模块结果的分析。
那么如何避免正在执行的主模块在调用其他模块时,可以不用执行被调用的模块中的相关代码呢?一个比较笨的办法就是把那些代码全部删除,但是被调用的模块之前可能也是一个主模块,这样做如果之后再次用到这个模块中的代码必须得重写,比较麻烦。下面介绍利用内置属性__name__来解决这一问题。
前面我们介绍过Python为我们提供的各种内置函数,同样也为我们提供了内置属性,可以把它理解为一个Python为我们提供的一个全局变量。内置属性__name__表示当前模块的模块名,如果是正在执行的主模块,那么__name__='__main__';如果是被调用模块那么__name__=模块名 下面我们再修改下operator.py中的代码,如下:
- def add(x,y):
- return x+y
- def subtract(x,y):
- return x-y
- def mul(x,y):
- return x*y
- def divide(x,y):
- return x/y
- print("operator-name:",__name__)
在最后我们添加了一句,print("operator-name:",name),即打印当前模块的内置属性__name__,主模块代码如下:
- import operator
- print("main:",__name__)
打印结果如下:
可以看到当调用模块operator时,执行了我们修改之后添加的语句print("operator-name:",__name__),打印出来的模块operator的__name__属性值为'operator',即模块名。主调用模块的__name__=='__main__',可见可以通过__name__属性来区分一个模块是主模块还是被调用模块。既然能够区分两者,那么通过判断__name__属性值,如果一个模块是被调用模块的话,相关代码就不执行,修改operator.py的代码如下:
- def add(x,y):
- return x+y
- def subtract(x,y):
- return x-y
- def mul(x,y):
- return x*y
- def divide(x,y):
- return x/y
- if __name__=='__main__':
- print(mul(5,6))
如上通过判断operator模块的内置属性是否为"__main__",如果是则表示operator为当前正在执行的主模块,可以执行operator模块中的相关代码;否则就是被调用模块,不执行相关代码。主调用模块代码如下:
- import operator
- print(operator.add(2,3))
执行结果如下:
通过打印结果可以看到,在主模块中调用operator模块时并没有执行operator模块中的相关代码,以上问题得到解决。
2.Python中模块的调用顺序
- s="zhangsan"
- print(str.capitalize(s))
打印结果如下:
下面我们在项目路径下定义一个与Python中str模块重名的模块,str.py。在这个自定义模块str中,我们定义一个函数capitalize(x),如下:
- def capitalize(x):
- return 'hello world'
自定义模块str中的capitalize(x)函数很简单,只是返回一个字符串"hello world".
下面是调用这个自定义str模块的代码:
- import str
- s="zhangsan"
- print(str.capitalize(s))
打印结果如下:
通过打印结果发现,Python调用的函数实质上是我们自定义模块str中的capitalize(x)函数,而不是Python中的内置函数capitalize(x),这其实与Python调用模块的顺序有关。
在Python中调用一个模块时,Python会先检查该模块是否是用户自定义的模块,如上我们自定义了一个模块str,这个模块与Python中lib文件夹下的str模块重名,可以说是因为重名,我们的自定义模块把Python中的预定义str模块给覆盖住了,所以最终调用的函数是自定义模块str中的capitalize(x)函数,这也提醒我们在自定义模块时不要与系统的预定义模块重名,以免引起不必要的麻烦。
3.包
可以看到,我们自定义了一个名为data的包,包下有一个模块food,food.py中的代码如下:
- def eat(x):
- print('I like to eat',x)
新建完包及包内模块后,那么如何调用模块中为我们提供的功能函数呢?
方法有三种。
方法一:
- import data.food
- data.food.eat('rice')
方法一,先导入模块,再调用模块中的函数;导入模块的方式为,包名.模块名,如data.food;调用函数的方式为包名.模块名.函数名,如data.food.eat("rice")。
打印结果如下:
方法二:
- import data.food as food
- food.eat('apple')
有时候我们在引入一个模块的时候,由于包的层层嵌套的问题,被引入模块可能要经过很多个包才能被被导入,比如data.fooddata.likefood.food,引入food这个模块经过了data,fooddata,likefood多个包,在调用模块food提供的函数时,也要写这么一大串,程序写起来很不方便,可读性也比较差。为了方便,我们可以为被导入模块起一个别名,如上import data.food as food 就是为被导入模块data.food起别名为food,调用函数的方法为模块别名.函数,如food.eat("apple"),程序打印结果如下:
方法三:
- from data.food import eat
- eat('barbecue')
有时候为了方便调用模块为我们提供的函数,也可以直接把函数引入,引入方法为from 包名.模块名 import 函数名,如from data.food import eat;这样就可以直接调用函数,而不需要在函数之前指定包名或模块名.更加方面可读.代码打印结果如下:
以上就是引入模块的三种方法,熟练使用它们可以方便高效的编写代码.
下一节我们将介绍正则表达式,敬请期待。