python基础之包、模块、命名空间和作用域
一、模块介绍
模块就是一组功能的集合体,我们的程序可以导入模块来复用模块里的功能。
模块的作用:
(1)从文件级别组织程序,更方便管理;随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用;
(2)拿来主义,提升开发效率同样的原理,我们也可以下载别人写好的模块然后导入到自己的项目中使用,这种拿来主义,可以极大地提升我们的开发效率。
二、创建及使用模块
1、创建一个模块sendmsg.py
def test1(): print("----test1-1------") print("----test1-2------") print("----test1-3------") def test2(): print("----test2-1------") print("----test2-2------") print("----test2-3------")
2、创建一个main.py,调用sendmsg中的函数
import sendmsg # 第一种导入方法: sendmsg.test1() # 需要先写模块名+调用;比如把工具箱拿过来用,需要再从工具箱里在取东西 sendmsg.test2()
# 第二种导入方法:
# 有时候我们只需要用到模块中的某个函数,只需要引入该函数即可,此时可以用下面方法实现: from 模块名 import 函数名1,函数名2....
from sendmsg import test1 test1()
注意:
通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。也就是说假如模块A中有函数function( ),在模块B中也有函数function( ),如果引入A中的function在先、B中的function在后,那么当调用function函数的时候,是去执行模块B中的function函数。
思考:为什么必须加上模块名调用呢?
因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名
from sendmsg import * #调用一个模块中的所有函数 test1() test2()
as起别名
from sendmsg import test1 as t1 t1()
包
包是一种管理python模块命名空间的形式,采用“点模块名称”;比如一个模块的名称是A.B,表示一个包A中的子模块B
在导入一个包的时候,python会根据sys.path中的目录来寻找这个包中包含的子目录;目录只有包含一个叫做__init__.py的文件才会被认作是一个包,主要是为了避免一些滥俗的名字不小心的影响搜索路径中的有效模块。
from . import FUNC from .. import FUNC
三、命名空间
1、命名空间的概念
命名空间是对一个名字起作用的范围
命名空间的本质:存放名字与值得绑定关系
2、命名空间的种类:
(1)内置命名空间(int string def print等)
就是Python解释器一启动就可以使用的名字存储在内置的命名空间中
内置的名字在启动解释器的时候被加载在内存里
(2)全局命名空间:位于模块的最上层
是在程序上到下被执行的过程依次加载到内存里
放置了我们设置的所有变量名和函数名
(3)局部命名空间:位于函数内
就是在函数内部定义的名字
当调用函数的时候,才会产生这个名称空间,随着函数执行的结束 这个命名空间就又消失了
3、三种命名空间之间的加载与取值顺序
加载顺序:
内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
访问顺序:
局部 --------> 全局 --------> 内置
在正常情况下,直接使用内置的名字
当我们在全局定义了和内置命名空间中同名的名字时,会使用全局的名字
(当我自己有的时候,我就不找我的上级要了)
如果自己没有,就找上一级要,上一级没有再找上一级,如果内置的命名空间都没有就报错
多个函数应该拥有多个独立的局部命名空间,不互相共享
四、作用域
1、作用域的概念
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
作用域
在之前学习变量的作用域时,经常会提到局部变量和全局变量,之所有称之为局部、全局,就是因为他们的自作用的区域不同,这就是作用域
2、局部变量(Locals)
def test(): a = 100 b = 200 print(locals()) #打印局部变量 test() --------------------------------------- {'a': 100, 'b': 200}
3、全局变量(global)
num = 5 def func(): global num # 加上这行把num变成了全局变量 num += 1 print(num) func() print(num)
4、全局变量和局部变量名字相同时,函数使用的是局部变量
a =1 b = 2 def func(): x = "aaa" y = 'bbb' print(locals()) #查看局部作用域所有名字用locals() print(globals()) func() #最后一步骤注释 print(globals()) # 查看全局作用域和内置有哪些名字 print(locals()) # 翻译成中文是本地的 所有和全局是一样的。 # 总结: #globals 永远打印全局的名字 #locals 输出什么是根据locals所在的位置
# 输出 {'x': 'aaa', 'y': 'bbb'} {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000008AAC1B62E8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/renyz02/Desktop/py_test1/20190916/main.py', '__cached__': None, 'a': 1, 'b': 2, 'func': <function func at 0x0000008AAC4B8BF8>} {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000008AAC1B62E8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/renyz02/Desktop/py_test1/20190916/main.py', '__cached__': None, 'a': 1, 'b': 2, 'func': <function func at 0x0000008AAC4B8BF8>} {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000008AAC1B62E8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/renyz02/Desktop/py_test1/20190916/main.py', '__cached__': None, 'a': 1, 'b': 2, 'func': <function func at 0x0000008AAC4B8BF8>}
例子1:
a =1 #a = 1 def func(a): #func(1) = 2 a = 2 #a = 2 return a #a = 2 a = func(a) #a = func(1);a = 1 print(a) #a = 2
例子2:
num = 100 nums = [11,22] def test(): #修改了执行,全局变量指向了一个新的地方(即100+100),需要使用global global num num += 100 def test2(): #只是在全局变量中增加了66,指向的空间未发生变化,则不需要使用global nums.append(66) print(num) print(nums) test() test2() print(num) print(nums)
总结:
在函数外边定义的变量叫做全局变量
全局变量能够在所有的函数中进行访问
如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的,小技巧强龙不压地头蛇
全局变量要定义在函数调用前,否则会报错。