模块-import--from...import...

什么是模块?

常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。

# import加载的模块分为四个通用类别
# 1、使用python编写的代码(.py文件)
# 2、已被编译为共享库或DLL的C或C++扩展
# 3、包好一组模块的包
# 4、使用C编写并链接到python解释器的内置模块

为什么要用模块?
因每次退出python解释器然后重新进入,那么你之前定义的函数或变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py 被称为脚本script

为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用。

如何使用模块

import --- 示例:在目录创建一个test_module.py文件,则模块名为:test_module

# test_module
print('test_module模块')

msg = 'Hello world!'

def read():
    print('test_module-->read()-->msg',msg)

def change():
    global msg msg='Hello Jerry'

开始使用 import 导入模块

import test_module

# 结果是:test_module模块

如果多次import同一个模块呢?

模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入,python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载大内存中的模块对象增加了一次引用,不会重新执行模块内的语句)

import test_module
import test_module
import test_module
import test_module
import test_module


# 结果:test_module模块

注意:我们可以从sys.modules中找到当前已经加载的模块,sys.modules是一个字典,内部包含模块名与模块对象的映射,该字典决定了导入模块时是否需要重新导入。
每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突。

# 测试一: msg 与 test_module不冲突
import test_module

msg = 'hello python'
print(test_module.msg)
# 测试一: msg 与 test_module不冲突
# 测试一: msg 与 test_module不冲突
import test_module

msg = 'hello python'
print(test_module.msg)

# 测试二:read 与 test_module不冲突
def read():
    print('hello python')

test_module.read()
# 测试二:read 与 test_module不冲突
# 测试一: msg 与 test_module不冲突
import test_module

# msg = 'hello python'
print(test_module.msg)

# 测试二:read 与 test_module不冲突
def read():
    print('hello python')

test_module.read()

# 测试三:执行test_change()操作的全局变量msg 仍然是test_module中的
msg = 'hello python'
test_module.change()
print(msg)
# 测试三:执行test_change()操作的全局变量msg 仍然是test_module中的

 首次模块导入的执行过程

首次导入模块test_module时会做三件事:

1.为源文件(test_module模块)创建新的名称空间,在test_module中定义的函数和方法若是使用到了global时访问的就是这个名称空间。

2.在新创建的命名空间中执行模块中包含的代码,见初始导入import test_module

# 1 提示:导入模块时到底执行了什么?
# 2 
# 3 In fact function definitions are also ‘statements’ that are ‘executed’; the execution of a module-level function definition enters the function name in the module’s global symbol table.
# 4 事实上函数定义也是“被执行”的语句,模块级别函数定义的执行将函数名放入模块全局名称空间表,用globals()可以查看

3.创建名字my_module来引用该命名空间

#这个名字和变量名没什么区别,都是‘第一类的’,且使用my_module.名字的方式可以访问my_module.py文件中定义的名字,my_module.名字与test.py中的名字来自两个完全不同的地方。

给模块取别名 as 别名

为模块 tset_module 起别名

import test_module as mymodule

mymodule.read() # 正常执行
test_module.read() # 执行报错,原因:已启用别名,相当于原来的test_module已经不存在了

示例二:

为已经导入的模块起别名的方式对编写可扩展的代码很有用,假设有两个模块xmlreader.py和csvreader.py,它们都定义了函数read_data(filename):用来从文件中读取一些数据,但采用不同的输入格式。可以编写代码来选择性地挑选读取模块,例如

if file_format == 'xml':
     import xmlreader as reader
elif file_format == 'csv':
     import csvreader as reader
data=reader.read_date(filename)
示例二

一行导入多个模块

import os,re,test_module

from... import ...

# 对比import test_module,会将源文件的名称空间'test_module'带到当前名称空间中,使用时必须是test_module.名字的方式

# 而from 语句相当于import,也会创建新的名称空间,但是将test_module中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了
from test_module import read

read()

注意:如果当前有定义同名的函数或变量,会将模块内定义的的函数或变量进行覆盖

from test_module import read

def read():
    print('hello')
read()

需要特别强调的一点是:python中的变量赋值不是一种存储操作,而只是一种绑定关系,如下:

from test_module import read,msg

msg = 'hello jerry' # 将当前位置的名字msg绑定到了 hello jerry
print(msg) # 打印当前的名字
read() # 读取test_module.py中的名字msg,仍然是hello world

这种方式导入也支持别名 as

from test_module import read as testread

testread() # 正常运行
read() # 报错

 from ... import *

# 可以引入所有的内容,并且调用,但是安全性差
from test_module import *
print(msg)
read()

为了使用 import * 更安全 接着引入__all__ = [list] 格式必须是__all__ = 列表 ,列表里面是你这个模板文件中的变量名或函数名,且是字符串格式

# test_module
__all__ = ['msg']
print('test_module模块')

msg = 'Hello world!'

def read():
    print('test_module-->read()-->msg',msg)
# 改进后,__all__ 里面的变量名或函数名不会被导入
from test_module import *
print(msg)  #  因为__all__=['msg'] 才会被导入,所以可以引用
read() # 因为没有将read写入到__all__中 所以无法导入

 把模块当脚本使用

我们可以通过模块的全局变量__name__来查看模块名: 当做脚本运行: __name__ 等于'__main__'

当做模块导入: __name__= 模块名

作用:用来控制.py

文件在不同的应用场景下执行不同的逻辑

if __name__ == '__main__':

# test_module
# __all__ = ['msg']
print('test_module模块')

msg = 'Hello world!'

def read():
    print('test_module-->read()-->msg',msg)

def test():
    print("这是__main__的作用")

if __name__ == '__main__':
    print('hehehehehe')
    test()
# 改进后,__all__ 里面的变量名或函数名不会被导入
from test_module import *
print(msg)  #  因为__all__=['msg'] 不会被导入,所有无法引用
read()
test()
# if 里的信息不会输出

 

posted on 2019-03-12 16:21  Jerry-Wang  阅读(263)  评论(0)    收藏  举报