python函数进阶小结_python函数的进阶

本文深入探讨了Python函数的动态参数,包括*args用于位置参数和**kwargs用于关键字参数的使用,以及它们在函数调用时的打散和聚合操作。同时,文章还介绍了Python函数中的命名空间、作用域规则,包括LEGB原则,并讲解了如何使用nonlocal和global关键字处理不同作用域的变量。通过实例详细解析了函数的局部和全局作用域,以及函数嵌套的执行顺序。最后,文章提到了内置函数globals()和locals()在查看作用域内容时的应用。
摘要由CSDN通过智能技术生成

形参角度:

万能参数

如果我们在传参数时不很清楚有哪些,或者说给一个函数传了很多实参,考虑用动态参数也叫万能参数。

万能参数,即动态参数,分为两种:动态接收位置参数 *args,动态接收关键字参数**kwargs.

#动态接收位置参数 *args

*【动态接收位置参数 *args:*args,约定俗成在*后使用args,PEP8规范中规定就使用args (这里起到魔法效果的是 * 而不是args)】

*【函数定义时,*代表聚合,它将所有的位置参数聚合成一个元组,赋值给了args,*args可以接受所有的位置参数。】

*【总结:*args只可以接受多个位置参数,并且返回一个元组。不能接受关键字参数。】

def eat(a,b,c,d):

print('我请你吃:%s,%s,%s,%s'%(a,b,c,d))

eat('蒸羊羔','蒸熊掌','蒸鹿邑','烧花鸭')#我请你吃:蒸羊羔,蒸熊掌,蒸鹿邑,烧花鸭

def eat(*args):

print('我请你吃:',args) #返回一个元组

print('我请你吃:%s,%s,%s,%s'%args)

eat('蒸羊羔儿','蒸熊掌','蒸鹿尾儿','烧花鸭')##只能接受位置参数,不能接受关键字参数

#结果:

我请你吃: ('蒸羊羔儿', '蒸熊掌', '蒸鹿尾儿', '烧花鸭')

我请你吃:蒸羊羔儿,蒸熊掌,蒸鹿尾儿,烧花鸭

#练习:传入函数中数量不定的int型数据,函数计算所有数的和并返回。

def my_sum(*args):

sum = 0

print(*args)#1 2 3 4 5

print(args)#(1, 2, 3, 4, 5)

for i in args: #计数思想

sum += i

return sum

print(my_sum(1,2,3,4,5))#15

#动态接收关键字参数: **kwargs

*【动态接收关键字参数: **kwargs ,**kwargs接受所有的关键字参数,然后将其转换成一个字典赋值给kwargs这个形参。】

*【函数定义时:**将所有的关键字参数聚合到一个字典,将这个字典赋值给了kwargs】

*【总结:**kwargs只能接受多个关键字参数,然后将其转换成一个字典。不能接受位置参数。】

def fuc(**kwargs):

print(kwargs)

fuc(name = '太白',age = 18,sex = '男')#只能接受关键字参数,不能接受位置参数

#{'name': '太白', 'age': 18, 'sex': '男'}

#动态参数的完整写法:万能参数:*args, **kwargs,

*【如果一个参数设置了动态参数,那么它可以接受所有的位置参数,以及关键字参数,这样就会大大提升函数拓展性,针对于实参参数较多的情况下,解决了一一对应的麻烦。】

def fuc(*args,**kwargs):

print(args)

print(kwargs)

fuc('蒸羊羔儿','蒸熊掌','蒸鹿尾儿','烧花鸭','烧雏鸡','烧子鹅',name = '太白',age = 18,sex = '男')

#结果:

('蒸羊羔儿', '蒸熊掌', '蒸鹿尾儿', '烧花鸭', '烧雏鸡', '烧子鹅')

{'name': '太白', 'age': 18, 'sex': '男'}

*的魔性用法。

*的魔性用法:函数中分为打散和聚合。函数外可以处理剩余的元素。

###打散和聚合:

1.聚合:在函数定义时,*代表聚合 。在args前面加一个* ,那么args可以接受多个位置参数,并且返回一个元组.(**kwargs也是同理将多个关键字参数转化成一个字典返回),所以在函数的定义时: *起到的是聚合的作用。

2.打散:在函数调用时,*代表打散:在实参角度的位置参数-->(可迭代对象:字符串,列表。元组)前面加*,相当于把这些实参拆解成的一个个的组成元素当作位置参数,然后传给args 。

在实参角度的位置参数-->字典前面加**

# 在函数的调用时,*代表打散。

def func(*args,**kwargs):

print(args) # (1,2,3,22,33)

print(kwargs)

func(*[1,2,3],*[22,33])

# (1, 2, 3, 22, 33)

# {}

func(*'fjskdfsa',*'fkjdsal')

# ('f', 'j', 's', 'k', 'd', 'f', 's', 'a', 'f', 'k', 'j', 'd', 's', 'a', 'l')

# {}

func(**{'name': '太白'},**{'age': 18})

# ()

# {'name': '太白', 'age': 18}

##1:

针对*args,在实参角度的位置参数--可迭代对象(字符串,列表,元组)前面加*,相当于把这些实参拆解成的一个个的组成元素当作位置参数,然后传给args

'''你如何将三个数据(这三个数据都是可迭代对象类型)s1 = 'alex',l1 = [1, 2, 3, 4],tu1 = ('武sir', '太白', '女神',)的每一元素传给动态参数*args?'''

s1 = 'alex'

l1 = [1, 2, 3, 4]

tu1 = ('武sir', '太白', '女神',)

def fuc(*args):

print(args)

fuc(s1,l1,tu1)#('alex', [1, 2, 3, 4], ('武sir', '太白', '女神'))

fuc(*s1,*l1,*tu1)#('a', 'l', 'e', 'x', 1, 2, 3, 4, '武sir', '太白', '女神')

##2:

针对**kwargs,在实参角度的位置参数---字典前面加**,将字典变为关键字变量,再由**kwargs变为字典

##

def func(**kwargs):

print(kwargs)

dic1 = {'name': '太白', 'age': 18}

dic2 = {'hobby': '喝茶', 'sex': '男'}

func(**dic1,**dic2)

#结果:

{'name': '太白', 'age': 18, 'hobby': '喝茶', 'sex': '男'}

##

def func(*args,**kwargs):

print(args)

print(kwargs)

dic1 = {'name': '太白', 'age': 18}

dic2 = {'hobby': '喝茶', 'sex': '男'}

func(**dic1,**dic2)

#结果:

()

{'name': '太白', 'age': 18, 'hobby': '喝茶', 'sex': '男'}

func(dic1,dic2)

#结果:

({'name': '太白', 'age': 18}, {'hobby': '喝茶', 'sex': '男'})

{}

3.函数外处理剩余的元素。

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]

仅限关键字参数(了解)

*【形参角度第四个参数:仅限关键字参数,形参的仅限关键字参数只接受实参的关键字传的参数】

*【仅限关键字参数是python3x更新的新特性,他的位置要放在*args后面,**kwargs前面,类似于位置参数,它与默认参数的前后顺序无所谓,它只接受关键字传的参数】

def func(a,b,*args,sex= '男',c,**kwargs,): #与默认参数的前后顺序无所谓,他的位置要放在*args后面,**kwargs前面

print(a,b)

print(args) #元组

print(sex)

print(c) #形参的仅限关键字参数,只能接受实参的关键字参数

print(kwargs)

func(1,2,3,4,5,6,7,sex='女',name='Alex',age=80,c='666')

#结果:

1 2

(3, 4, 5, 6, 7)

666

{'name': 'Alex', 'age': 80}

def func(a,b,*args,d,sex = '男',**kwargs): #与默认参数的前后顺序无所谓,他的位置要放在*args后面,**kwargs前面

print(a,b)

print(args)

print(sex)

print(d)

print(kwargs)

func(1,2,3,4,5,d=1,sex='女',name='alex',age=80)

形参角度的参数的顺序。

形参角度最终的顺序为:

位置参数,*args,仅限关键字参数,默认参数,**kwargs

或: 位置参数,*args,默认参数,仅限关键字参数,**kwargs

#

位置参数必须在前面,即 :位置参数,默认参数

# *args 的位置?

【动态参数*args肯定不能放在位置参数前面,这样我的位置参数的参数就接收不到具体的实参了。】

【因为*args全部接收完了,所以动态参数必须在位置参数后面。】

【*args一定要在位置参数与默认值参数中间:位置参数,*args,默认参数】

#错:

def func(*args,a,b,sex= '男'):

print(a,b)

func(1,2,3,4)

# 错:args得到实参的前提,sex必须被覆盖了。

def func(a,b,sex= '男',*args,):

print(a,b)

print(sex)

print(args)

func(1,2,3,4,5,6,7,)

#对:

def func(a, b, *args, sex='男'):

print(a, b)

print(args)

print(sex)

func(1, 2, 3, 4, 5, 6, 7, sex='女')

#结果:

1 2

(3, 4, 5, 6, 7)

# **kwargs 位置?

def func(a,b,*args,sex= '男',**kwargs,):

print(a,b)

print(sex)

print(args)

print(kwargs)

func(1,2,3,4,5,6,7,sex='女',name='Alex',age=80)

# 1 2

# 女

# (3, 4, 5, 6, 7)

# {'name': 'Alex', 'age': 80}

2.名称空间。

全局名称空间,局部名称空间

存放名字与值的关系’的空间------>命名空间

全局命名空间:代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;(py文件中,存放变量名与值的关系的一个空间叫做全局名称空间)

局部名称空间:当执行一个函数时,内存中会临时开辟一个空间,临时存放函数中的变量与值的关系,这个叫做临时名称空间【随着函数的执行的开始而创建,随着函数执行的结束而消失】

内置名称空间:内置名称空间存放的就是python源码给你提供的一些内置函数等拿来即用的特殊的变量:input,print,list等。

​ 在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空。

3148abcaa228580e

3148abcaa228580e

#名称空间;命名空间。

a = 1

b = 2

def func():

f = 5

print(f)

c = 3

func()

python分为三个空间:

# 内置名称空间(builtins.py)

# 全局名称空间(当前py文件)

# 局部名称空间(函数,函数执行时才开辟)

2.加载顺序,取值顺序。

# 加载顺序:

内置名称空间 ---> 全局名称空间 ----> 局部名称空间(函数执行时)

在启动python解释器之后,即使没有创建任何的变量或者函数,还是会有一些函数直接可以用的比如abs(-1),max(1,3)等等,在启动Python解释器的时候,就已经导入到内存当中供我们使用,所以肯定是先加载内置名称空间,然后就开始从文件的最上面向下一行一行执行,此时如果遇到了初始化变量,就会创建全局名称空间,将这些对应关系存放进去,然后遇到了函数执行时,在内存中临时开辟一个空间,加载函数中的一些变量等等。所以这三个空间的加载顺序为:内置命名空间(程序运行伊始加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载。

# 取值顺序(就近原则) 单向不可逆 LEGB原则

(从局部找时)局部名称空间 ---> 全局名称空间 ---> 内置名称名称空间

取值顺序就是引用一个变量,先从哪一个空间开始引用。这个有一个关键点:从哪个空间开始引用这个变量。

# 如果你在全局名称空间引用一个变量,先从全局名称空间引用,全局名称空间如果没有,才会向内置名称空间引用。

# 如果你在局部名称空间引用一个变量,先从局部名称空间引用。

# 局部名称空间如果没有,才会向全局名称空间引用,全局名称空间在没有,就会向内置名称空间引用。

所以空间的取值顺序与加载顺序是相反的,取值顺序满足的就近原则,从小范围到大范围一层一层的逐步引用。

input = '太白金星'

def func():

input = 'alex'

print(input)

func()

#alex

input = '太白金星'

def func():

input = 'alex'

func()

print(input)#太白金星

3.作用域。

# 两个作用域:

1.全局作用域 :内置名称空间 全局名称空间。在整个文件的任何位置都可以使用(遵循 从上到下逐⾏执行).

2.局部作用域:局部名称空间。在函数内部可以使用.

# 全局作用域只能引用全局作用域的变量。全局变量要放在py文件的开头。

# 局部作用域可以引用全局作用域的变量, 局部作用域不能改变全局变量。

date = '周五'

def func():

a = 666

print(date)#周五

print(a)#666

func()

print(a)#NameError: name 'a' is not defined

# 局部作用域不能改变全局变量。

局部作用域不能改变全局作用域的变量,当python解释器读取到局部作用域时,发现了你对一个变量进行修改的操作,

解释器会认为你在局部已经定义过这个局部变量了,他就从局部找这个局部变量,报错了。

#错【面试必考】

count = 1

def func():

count += 2

print(count)

func() # UnboundLocalError: local variable 'count' referenced before assignment 变量“count” 在创建前引用

# 局部作用域可以引用父级作用域的变量,但是不能改变父级作用域的变量。

def func():

count = 1

def inner():

print(count) #1

inner()

func()

#错【面试必考】

def func():

count = 1

def inner():

count += 1

print(count)

inner()

func()

#UnboundLocalError: local variable 'count' referenced before assignment

3.函数的嵌套(高阶函数)

# 例1:

def func1():

print('in func1')

print(3)

def func2():

print('in func2')

print(4)

func1()

print(1)

func2()

print(2)

# in func1 3 1 in func2 4 2

# 例2:

def func1():

print('in func1')

print(3)

def func2():

print('in func2')

func1()

print(4)

print(1)

func2()

print(2)

#1 in func2 in func1 3 4 2

# 例3:

def fun2():

print(2)

def fun3():

print(6)

print(4)

fun3()

print(8)

print(3)

fun2()

print(5)

#3 2 4 6 8 5

# glbals() locals()

这两个内置函数可以反映作用域的内容,有助于我们理解作用域的范围。

globals(): 以字典的形式返回全局作用域所有的变量对应关系。

locals(): 以字典的形式返回当前作用域的变量的对应关系。

4.内置函数 globals() locals()

a = 1

b = 2

def func():

name = 'alex'

age = 73

print(globals()) # 返回的是字典:字典里面的键值对:全局作用域的所有内容。

print(locals()) # 返回的是字典:字典里面的键值对:当前作用域的所有的内容。

print(globals()) # 返回的是字典:字典里面的键值对:全局作用域的所有内容。

print(locals()) # 返回的是字典:字典里面的键值对:当前作用域的所有的内容。

func()

5.关键字:nonlocal global。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值