新闻类网站开发多久,安徽阜阳网站建设,微信小说分销平台,璧山职教中心示范校建设网站1. 今日内容
1.1 函数的参数
*的魔性用法
函数形参最终顺序
1.2名称空间
全局名称空间#xff0c;局部名称空间#xff0c;内置名称空间
取值顺序与加载顺序
作用域
内置函数#xff1a;globals() locals()
1.3 高阶函数#xff08;函数的嵌套#xff09;
1.4关键字#…1. 今日内容
1.1 函数的参数
*的魔性用法
函数形参最终顺序
1.2名称空间
全局名称空间局部名称空间内置名称空间
取值顺序与加载顺序
作用域
内置函数globals() locals()
1.3 高阶函数函数的嵌套
1.4关键字global nonlocal
2. 内容详细
2.1 函数的参数
昨天我们从形参角度讲了两种参数一个是位置参数位置参数主要是实参与形参从左至右一一对应一个是默认值参数默认值参数如果实参不传参则形参使用默认参数。那么无论是位置参数还是默认参数函数调用时传入多少实参我必须写等数量的形参去对应接收 如果不这样那么就会报错
def eat(a,b,c,):
print(我请你吃,a,b,c)
eat(蒸羊羔,蒸熊掌,蒸鹿尾儿,烧花鸭) # 报错
如果我们在传参数的时候不很清楚有哪些的时候,或者说给一个函数传了很多实参,我们就要对应写很多形参,这样很麻烦怎么办,我们可以考虑使用动态参数也叫万能参数
2.11 形参的第三种:动态参数
动态参数分为两种:动态接受位置参数 *args动态接收关键字参数**kwargs.
动态接收位置参数*args
我们按照上面的例子继续写如果我请你吃的内容很多但是我又不想用多个参数接收那么我就可以使用动态参数*args
def eat(*args):
print(我请你吃,args)
eat(蒸羊羔儿,蒸熊掌,蒸鹿尾儿,烧花鸭,烧雏鸡,烧子鹅)
# 运行结果
#我请你吃 (蒸羊羔儿, 蒸熊掌, 蒸鹿尾儿, 烧花鸭, 烧雏鸡, 烧子鹅)
解释一下上面参数的意义首先来说argsargs就是一个普通的形参但是如果你在args前面加一个那么就拥有了特殊的意义在python中除了表示乘号他是有魔法的。args这样设置形参那么这个形参会将实参所有的位置参数接收放置在一个元组中并将这个元组赋值给args这个形参这里起到魔法效果的是 * 而不是argsa也可以达到刚才效果但是我们PEP8规范中规定就使用args约定俗成的。练习传入函数中数量不定的int型数据函数计算所有数的和并返回。
def my_max(*args):
n 0
for i in args:
n i
return n
动态接收关键字参数: **kwargs
实参角度有位置参数和关键字参数两种python中既然有*args可以接受所有的位置参数那么肯定也有一种参数接受所有的关键字参数那么这个就是kwargs同理这个是具有魔法用法的kwargs约定俗成使用作为形参。举例说明**kwargs是接受所有的关键字参数然后将其转换成一个字典赋值给kwargs这个形参。
def func(**kwargs):
print(kwargs) # {name: 太白金星, sex: 男}
func(name太白金星,sex男)
我们看一下动态参数的完成写法
def func(*args,**kwargs):
print(args) # (蒸羊羔儿, 蒸熊掌, 蒸鹿尾儿)
print(kwargs) # {name: 太白金星, sex: 男}
func(蒸羊羔儿, 蒸熊掌, 蒸鹿尾儿,name太白金星,sex男)
如果一个参数设置了动态参数那么他可以接受所有的位置参数以及关键字参数这样就会大大提升函数拓展性针对于实参参数较多的情况下解决了一一对应的麻烦。
2.12 *的魔性用法
刚才我们研究了动态参数其实有的同学对于魔法用法 * 比较感兴趣那么那的魔性用法不止这么一点用法我们继续研究
函数中分为打散和聚合。
函数外可以处理剩余的元素。
函数的打散和聚合
聚合
刚才我们研究了在函数定义时如果我只定义了一个形参称为args那么这一个形参只能接受几个实参 是不是只能当做一个位置参数对待它只能接受一个参数
def eat(args):
print(我请你吃,args) # 我请你吃 蒸羊羔儿
eat(蒸羊羔儿)
但是如果我给其前面加一个* 那么args可以接受多个实参并且返回一个元组对吧 **kwargs也是同理将多个关键字参数转化成一个字典返回所以在函数的定义时 *起到的是聚合的作用。
打散
此时不着急给大家讲这个打散而是出一个小题你如何将三个数据这三个数据都是可迭代对象类型s1 alex,l1 [1, 2, 3, 4], tu1 (武sir, 太白, 女神,)的每一元素传给动态参数*args就是args最终得到的是 (a,l,e,x, 1, 2, 3, 4,武sir, 太白, 女神,?有人说这还不简单么我直接传给他们不就行了
s1 alex
l1 [1, 2, 3, 4]
tu1 (武sir, 太白, 女神,)
def func(*args):
print(args) # (alex, [1, 2, 3, 4], (武sir, 太白, 女神))
func(s1,l1,tu1)
这样肯定是不行他会将这个三个数据类型当成三个位置参数传给args没有实现我的要求。
好像你除了直接写没有别的什么办法那么这里就得用到我们的魔法用法 *
s1 alex
l1 [1, 2, 3, 4]
tu1 (武sir, 太白, 女神,)
def func(*args):
print(args) # (a, l, e, x, 1, 2, 3, 4, 武sir, 太白, 女神)
func(*s1,*l1,*tu1)
你看此时是函数的执行时我将你位置参数的实参可迭代类型前面加上相当于将这些实参给拆解成一个一个的组成元素当成位置参数然后传给args,这时候这个好像取到的是打散的作用。所以在函数的执行时**起到的是打散的作用。
dic1 {name: 太白, age: 18}
dic2 {hobby: 喝茶, sex: 男}
def func(**kwargs):
print(kwargs) # {name: 太白, age: 18, hobby: 喝茶, sex: 男}
func(**dic1,**dic2)
*处理剩下的元素
*除了在函数中可以这样打散聚合外函数外还可以灵活的运用
# 之前讲过的分别赋值
a,b (1,2)
print(a, b) # 1 2
# 其实还可以这么用
a,*b (1, 2, 3, 4,)
print(a, b) # 1 [2, 3, 4]
*rest,a,b range(5)
print(rest, a, b) # [0, 1, 2] 3 4
print([1, 2, *[3, 4, 5]]) # [1, 2, 3, 4, 5]
2.13 形参的顺序
到目前为止从形参的角度我们讲了位置参数默认值参数动态参数*args**kwargs还差一种参数需要讲完形参顺序之后引出。先不着急我们先看看已经讲的这些形参他的排列顺序是如何的呢
首先位置参数与默认参数他两个的顺序我们昨天已经确定了位置参数必须在前面即 位置参数默认参数。
那么动态参数*args**kwargs放在哪里呢
动态参数*args肯定不能放在位置参数前面这样我的位置参数的参数就接收不到具体的实参了
# 这样位置参数a,b始终接收不到实参了因为args全部接受完了
def func(*args,a,b,sex男):
print(args)
print(a,b)
func(1, 2, 3, 4, 5)
那么动态参数必须在位置参数后面他可以在默认参数后面么
# 这样也不行我的实参的第三个参数始终都会将sex覆盖掉这样失去了默认参数的意义。
def func(a,b,sex男,*args,):
print(args) # (4, 5)
print(sex) # 3
print(a,b) # 1 2
func(1, 2, 3, 4, 5)
所以*args一定要在位置参数与默认值参数中间位置参数*args默认参数。
那么我的kwargs放在哪里kwargs可以放在默认参数前面么
# 直接报错因为**kwargs是接受所有的关键字参数如果你想改变默认参数sex你永远也改变不了因为
# 它会先被**kwargs接受。
def func(a,b,*args,**kwargs,sex男,):
print(args) # (4, 5)
print(sex) # 3
print(a,b) # 1 2
print(kwargs)
func(1, 2, 3, 4, 5)
所以截止到此所有形参的顺序为位置参数*args默认参数**kwargs。
2.14 形参的第四种参数仅限关键字参数
仅限关键字参数是python3x更新的新特性他的位置要放在*args后面kwargs前面如果有kwargs也就是默认参数的位置它与默认参数的前后顺序无所谓它只接受关键字传的参数
# 这样传参是错误的因为仅限关键字参数c只接受关键字参数
def func(a,b,*args,c):
print(a,b) # 1 2
print(args) # (4, 5)
# func(1, 2, 3, 4, 5)
# 这样就正确了
def func(a,b,*args,c):
print(a,b) # 1 2
print(args) # (3, 4)
print(5)
func(1, 2, 3, 4, c5)
这个仅限关键字参数从名字定义就可以看出他只能通过关键字参数传参其实可以把它当成不设置默认值的默认参数而且必须要传参数不传就报错。
所以形参角度的所有形参的最终顺序为位置参数*args默认参数仅限关键字参数**kwargs。
课间考一道题
def foo(a,b,*args,c,sexNone,**kwargs):
print(a,b)
print(c)
print(sex)
print(args)
print(kwargs)
# foo(1,2,3,4,c6)
# foo(1,2,sex男,namealex,hobbyold_woman)
# foo(1,2,3,4,namealex,sex男)
# foo(1,2,c18)
# foo(2, 3, [1, 2, 3],c13,hobby喝茶)
# foo(*[1, 2, 3, 4],**{name:太白,c:12,sex:女})
2.2 名称空间作用域
2.21 名称空间
接下来我们讲的内容理论性的偏多就是从空间角度内存级别去研究python。首先我们看看什么是全局名称空间
在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空.
我们首先回忆一下Python代码运行的时候遇到函数是怎么做的从Python解释器开始执行之后就在内存中开辟里一个空间每当遇到一个变量的时候就把变量名和值之间对应的关系记录下来但是当遇到函数定义的时候解释器只是象征性的将函数名读如内存表示知道这个函数存在了至于函数内部的变量和逻辑解释器根本不关心。
等执行到函数调用的时候Python解释器会再开辟一块内存来储存这个函数里面的内容这个时候才关注函数里面有哪些变量而函数中的变量回储存在新开辟出来的内存中函数中的变量只能在函数内部使用并且会随着函数执行完毕这块内存中的所有内容也会被清空。
我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。
代码在运行伊始创建的存储“变量名与值的关系”的空间叫做全局命名空间
在函数的运行中开辟的临时的空间叫做局部命名空间也叫做临时名称空间。
现在我们知道了py文件中存放变量与值的关系的一个空间叫做全局名称空间而当执行一个函数时内存中会临时开辟一个空间临时存放函数中的变量与值的关系这个叫做临时名称空间或者局部名称空间。
其实python还有一个空间叫做内置名称空间内置名称空间存放的就是一些内置函数等拿来即用的特殊的变量inputprintlist等等所以我们通过画图捋一下那么这就是python中经常提到的三个空间。
总结:
\1. 全局命名空间-- 我们直接在py文件中, 函数外声明的变量都属于全局命名空间
\2. 局部命名空间-- 在函数中声明的变量会放在局部命名空间
\3. 内置命名空间-- 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间
2.22 加载顺序
所谓的加载顺序就是这三个空间加载到内存的先后顺序也就是这个三个空间在内存中创建的先后顺序你想想他们能是同时创建么肯定不是的那么谁先谁后呢我们捋顺一下在启动python解释器之后即使没有创建任何的变量或者函数还是会有一些函数直接可以用的比如abs(-1),max(1,3)等等在启动Python解释器的时候就已经导入到内存当中供我们使用所以肯定是先加载内置名称空间然后就开始从文件的最上面向下一行一行执行此时如果遇到了初始化变量就会创建全局名称空间将这些对应关系存放进去然后遇到了函数执行时在内存中临时开辟一个空间加载函数中的一些变量等等。所以这三个空间的加载顺序为内置命名空间(程序运行伊始加载)-全局命名空间(程序运行中从上到下加载)-局部命名空间(程序运行中调用时才加载。
2.23 取值顺序
取值顺序就是引用一个变量先从哪一个空间开始引用。这个有一个关键点从哪个空间开始引用这个变量。我们分别举例说明
# 如果你在全局名称空间引用一个变量先从全局名称空间引用全局名# 称空间如果没有才会向内置名称空间引用。
input 666
print(input) # 666
# 如果你在局部名称空间引用一个变量先从局部名称空间引用
# 局部名称空间如果没有才会向全局名称空间引用全局名称空间在没有就会向内置名称空间引用。
input 666
print(input) # 666
input 666
def func():
input 111
print(input) # 111
func()
所以空间的取值顺序与加载顺序是相反的取值顺序满足的就近原则从小范围到大范围一层一层的逐步引用。2.24 作用域
作用域就是作用范围, 按照生效范围来看分为全局作用域和局部作用域
全局作用域: 包含内置命名空间和全局命名空间. 在整个文件的任何位置都可以使用(遵循 从上到下逐⾏执行).
局部作用域: 在函数内部可以使用.
作⽤域命名空间:
1. 全局作用域: 全局命名空间 内置命名空间
2. 局部作⽤域: 局部命名空间
2.25 内置函数globals(),locals()
这两个内置函数放在这里讲是在合适不过的他们就直接可以反映作用域的内容有助于我们理解作用域的范围。
globals(): 以字典的形式返回全局作用域所有的变量对应关系。
locals(): 以字典的形式返回当前作用域的变量的对应关系。
这里一个是全局作用域一个是当前作用域一定要分清楚接下来我们用代码验证
# 在全局作用域下打印则他们获取的都是全局作用域的所有的内容。
a 2
b 3
print(globals())
print(locals()){__name__: __main__, __doc__: None, __package__: None,
__loader__: _frozen_importlib_external.SourceFileLoader object at 0x000001806E50C0B8,
__spec__: None, __annotations__: {},
__builtins__: ,
__file__: D:/lnh.python/py project/teaching_show/day09~day15/function.py,
__cached__: None, a: 2, b: 3}
# 在局部作用域中打印。
a 2
b 3
def foo():
c 3
print(globals()) # 和上面一样还是全局作用域的内容
print(locals()) # {c: 3}
foo()
2.3 高阶函数函数的嵌套
其实我们见到了嵌套这个词不陌生之前我们讲过列表的嵌套列表的嵌套就是一个列表中还有列表可能那个列表中还有列表......那么顾名思义函数的嵌套就是一个函数中还有函数。
想要玩明白函数的嵌套关键点只要遇见了函数名()就是函数的调用. 如果没有就不是函数的调用吃透这一点就算明白了。那么我们举例练习找同学依次说出下面代码的执行顺序
# 例1
def func1():
print(in func1)
print(3)
def func2():
print(in func2)
print(4)
func1()
print(1)
func2()
print(2)
# 例2
def func1():
print(in func1)
print(3)
def func2():
print(in func2)
func1()
print(4)
print(1)
func2()
print(2)
# 例3
def fun2():
print(2)
def fun3():
print(6)
print(4)
fun3()
print(8)
print(3)
fun2()
print(5)
2.4 关键字global、nonlocal
global
讲这个关键字之前先给大家看一个现象
a 1
def func():
print(a)
func()
a 1
def func():
a 1 # 报错
func()
局部作用域对全局作用域的变量此变量只能是不可变的数据类型只能进行引用而不能进行改变只要改变就会报错但是有些时候我们程序中会遇到局部作用域去改变全局作用域的一些变量的需求这怎么做呢这就得用到关键字globalglobal第一个功能在局部作用域中可以更改全局作用域的变量。
count 1
def search():
global count
count 2
search()
print(count)
利用global在局部作用域也可以声明一个全局变量。
def func():
global a
a 3
func()
print(a)
所以global关键字有两个作用
1声明一个全局变量。
2在局部作用域想要对全局作用域的全局变量进行修改时需要用到 global(限于字符串数字)。
nonlocal
nonlocal是python3x新加的功能与global用法差不多就是在局部作用域如果想对父级作用域的变量进行改变时需要用到nonlocal当然这个用的不是很多了解即可。
def add_b():
b 42
def do_global():
b 10
print(b)
def dd_nonlocal():
nonlocal b
b b 20
print(b)
dd_nonlocal()
print(b)
do_global()
print(b)
add_b()
nonlocal关键字举例
nonlocal的总结
1不能更改全局变量。
2在局部作用域中对父级作用域或者更外层作用域非全局作用域的变量进行引用和修改并且引用的哪层从那层及以下此变量全部发生改变。