7 模块与包

7 模块与包

Python中的模块和包

  • 一个py文件就是一个模块,py文件的文件名就是模块名。

  • 在 Python 里为了对模块分类管理,就需要划分不同的文件夹。多个有联系的模块可以将其放到同一个文件夹下,为了称呼方便,一般把 Python 里的一个代码文件夹称为一个包。

7.1 导入模块

  1. 导入模块有五种方式
  • import 模块名
  • from 模块名 import 功能名
  • from 模块名 import *
  • import 模块名 as 别名
  • from 模块名 import 功能名 as 别名

下面来挨个的看一下。

  1. import

在Python中用关键字import来引入某个模块,比如要引入系统模块 math,就可以在文件最开始的地方用import math来引入。

语法:

import 模块1,模块2,...  # 导入方式

模块名.函数名()  # 使用模块里的函数

  • 想一想:

    为什么必须加上模块名调用函数呢?

  • 答:

    因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名

示例:

import math

#这样才能正确输出结果
print math.sqrt(2)

#这样会报错
print(sqrt(2))

  1. from…import…

有时候我们只需要用到模块中的某个函数,只需要引入该函数即可,此时可以用下面方法实现:

from 模块名 import 函数名1,函数名2....

不仅可以引入函数,还可以引入一些全局变量、类等

  • 注意:

    通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。也就是说假如模块A中有函数function( ),在模块B中也有函数function( ),如果引入A中的function在先、B中的function在后,那么当调用function函数的时候,是去执行模块B中的function函数。

例如,要导入模块fib的fibonacci函数,使用如下语句:

from fib import fibonacci

注意

  • 不会把整个fib模块导入到当前的命名空间中,它只会将fib里的fibonacci单个函数引入
  1. from … import *(不推荐使用)

把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:

from modname import *

注意

  • 这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
  1. as 别名

当导入的模块名、变量、方法等与当前文件的模块名、变量、方法等重名,可以使用 as 来取新名,之后在当前文件中调用需要使用新名

  • 可以给模块名起新的模块名:import 模块名 as 新模块名
  • 可以给变量、方法起新的名字:from 模块名 import 变量|方法 as 新名
In [1]: import time as tt  # 导入模块时设置别名为 tt

In [2]: time.sleep(1)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-07a34f5b1e42> in <module>()
----> 1 time.sleep(1)

NameError: name 'time' is not defined

In [3]: 

In [3]: tt.sleep(1)  # 使用别名才能调用方法

In [4]: 

In [4]: from time import sleep as sp  # 导入方法时设置别名

In [5]: sleep(1)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-5-82e5c2913b44> in <module>()
----> 1 sleep(1)

NameError: name 'sleep' is not defined

In [6]: 

In [6]: sp(1)  # 使用别名才能调用方法

In [7]:

补充:

哪些内容可在模块中使用?

答:所有在在指定if语句外的全局变量

导入模块的原理:

  • 当使用import或者from…import…导入模块的时候,系统会自动将被导入的模块中所有的代码都执行一遍。

import 和 include 的区别?

  • 共同点:都是导入另外模块到当前文件,并执行;

  • 不同点:当重复导入同一个模块时,include 每导入一次执行一次模块内容,但import重复导入只执行一次。

循环导入的问题(既在test1.py中导入test2.py,在test2.py中执行test1.py):

  • 在使用include时会发生循环引用,造成死循环;
  • 在使用import时不存在循环导入的问题 ,因为import自带查重功能,只会导入一次。

怎么选择性的执行被导入的内容?

  • 当导入的模块存在较为复杂的,增加了当前文件负担的内容时,需要在导入的模块内写入if __name__ == '__main__':,将不导入的内容写入if语句中,if语句外的内容会作为模块内容导入并执行。
  • if __name__ == '__main__'的原理:
  • 每个模块都有一个属性:__name__,这个属性是用来保存当前模块的名字;__name__默认值就是模块名(模块对应的py文件的文件名)。当我们直接执行某个模块的时候,这个模块的__name__属性就会自动变成__main__

7.2 制作模块

搜索路径

要自定义模块,首先要确定代码存放的位置可以被 Python 解释器找到。比如把一个 py 文件放在 U 盘里,在把 U 盘拔掉,那肯定是没法再导入了。

当你导入一个模块,Python解析器按照搜索路径来查找 py 文件,也就是说我们的 py 文件必须在模块搜索路径的某一个文件夹里。

  • 模块搜索路径存储在sys模块的sys.path变量中。

在这里插入图片描述

  • 变量里包含当前目录,以及由安装过程决定的默认目录。所以在习惯上,我们会把自己写的代码放到同一个项目文件夹。
  1. 定义自己的模块

在Python中,每个Python文件都可以作为一个模块,模块的名字就是文件的名字。也就是说自定义模块名必须要符合标识符命名规则。

比如有这样一个文件test.py,在test.py中定义了函数add

def add(a,b):
    return a+b
Copy
  1. 调用自己定义的模块

那么在其他文件中就可以先import test,然后通过test.add(a,b)来调用了,当然也可以通过from test import add来引入

import test

result = test.add(11,22)
print(result)
Copy
  1. 使用 __name__ 变量来写测试模块

在实际开中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在py文件中添加一些测试信息,例如:

def add(a,b):
    return a+b

# 用来进行测试
ret = add(12,22)
print('int test.py file,,,,12+22=%d'%ret)
Copy

如果此时,在其他py文件中引入了此文件的话,想想看,测试的那段代码是否也会执行呢!

import test

result = test.add(11,22)
print(result)
Copy

运行现象:
在这里插入图片描述

至此,可发现test.py中的测试代码,应该是单独执行test.py文件时才应该执行的,不应该是其他的文件中引用而执行

为了解决这个问题,python在执行一个文件时有个变量__name__

直接运行此文件

在这里插入图片描述
在其他文件中import此文件
在这里插入图片描述
总结:

  • 可以根据name变量的结果能够判断出,是直接执行的python脚本还是被引入执行的,从而能够有选择性的执行测试代码
    在这里插入图片描述

7.3 模块中的_all___

  1. 没有__all__

test.py文件:

class Test(object):
  def test(self):
    print('----Test类中的test方法------')
def test1():
  print('---test1函数---')
def test2():
  print('---test2函数---')

main.py文件:

from test import *
# 可以直接使用这个模块里的所有函数
test1()
test2()

# 可以使用这个模块里的类创建对象
a = Test()
a.test()

  1. 模块中有__all__

test.py文件内容

# 给 test.py 文件添加了__all__属性,只有这个属性里的内容会被导入
__all__ = ["Test","test2"]  # 由Test类和test2方法,没有test1方法

class Test(object):
  def test(self):
    print('----Test类中的test方法------')
def test1():
  print('---test1函数---')
def test2():
  print('---test2函数---')
Copy

main.py文件内容:

from test import *

# 可以使用test2方法
test2()

# 不能使用test1()方法,因为test1不在__all__属性里!
#test1()

# 可以使用Test这个类
a = Test()
a.test()
Copy

总结

  • 如果一个文件中有__all__变量,那么也就意味着__all__属性里没有列出的元素,在from xxx import *导入时,不会被导入。

7.4 Python中的包

什么是包?

  • 包的本质就是一种特殊的文件夹(a. 里面都是py文件;b.自带一个__init__.py的文件)
  1. 导入包的方式

现有以下包newmsg,包里由两个模块,分别是sendmsg.pyrecvmsg.py文件。在包的上级文件夹里,有一个test.py文件,目标是在test.py文件里引入newmsg的两个模块。

目录结构如下图所示:

在这里插入图片描述

sendmsg.py文件里的内容如下:

def send_msg():
  print('------sendmsg方法被调用了-------')

recvmsg.py文件里的内容如下:

def recv_msg():
  print('-----recvmsg方法被调用了--------')

可以使用以下几种方式来导入模块,使用模块里的方法。

1>. 直接使用包名.模块模块名导入指定的模块。

在这里插入图片描述

2>. 使用from xxx import xxx 方式导入指定模块。

在这里插入图片描述

3>. 使用__init__.py文件,导入包里的指定模块。

可以在newmsg里创建__init__.py文件,在该文件里导入指定的内容。

在这里插入图片描述

__init__.py文件里编写代码:

from . import sendmsg  # 导入指定的模块    . 代表的是当前文件夹

test.py文件里的代码

import newmsg # 导入时,只需要输入包名即可。在包名的__init__.py文件里,导入了指定模块
newmsg.sendmsg.sendm_msg()  # 可以直接调用对应的方法
# newmsg.recvmsg.recv_msg()   不可以使用 recvmsg 模块,因为 __init__.py文件里没有导入这个模块

4.> 使用__init__.py文件,结合__all__属性,导入包里的所有模块。

newmsg包里的__init__.py文件里编写代码:

__all__ = ["sendmsg","recvmsg"]  # 指定导入的内容

test.py文件代码:

from newmsg import *  # 将newmsg里的__inint__.py文件里,__all__属性对应的所有模块都导入
sendmsg.sendmsg()
recvmsg.recvmsg()

总结

  • 包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,那么这个文件夹就称之为
  • 有效避免模块名称冲突问题,让应用组织结构更加清晰
  1. __init__.py文件有什么用

__init__.py 控制着包的导入行为。__init__.py为空仅仅是把这个包导入,不会导入包中的模块。可以在__init__.py文件中编写内容。

newmsg/__init__.py文件:

print('hello world')

别的模块在引入这个包的时候,会自动调用这段代码。

在这里插入图片描述

  1. __all__

__init__.py文件中,定义一个__all__变量,它控制着 from 包名 import *时导入的模块。

newmsg/__init__.py文件:

__all__ = ['sendmsg','recvmsg']

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值