python 函数(一)
函数初识/名称空间/作用域/高阶函数/globals()local()/关键字global/nonlocal
函数初识
1、函数基本组成
写一个函数
def my_len(s): count = 0 for i in s: count += 1 return count s1 = "aldjfalkdjfd" s1_len = my_len(s1) print(s1_len)# def : 关键字
# my_len : 函数名
# s : 形参
# return : 返回 return 可以返回一个或多个值,返回一个值的时候,值是什么类型的数据,返回就是什么类型的数据,值是多个的时候,返回一个元祖
# 函数如果没有return的话返回None
# 函数的作用:减少重复的代码,提高代码的复用性,是代码更加简洁,可读性强
# 函数的执行:函数名()
2、函数传参
# 函数的传参:让函数封装的这个功能,盘活
# 实参,形参
def my_len(s): count = 0 for i in s: count += 1 return count s1 = "aldjfalkdjfd" s1_len = my_len(s1) print(s1_len)# s就是形参
# s1就是实参
3、实参角度分类
1、位置参数:
从左至右,一一对应
# 练习题
# 写一个函数,只接收两个int的参数,函数的功能是将较大的数返回 def big_num(a, b): if type(a) is int and type(b) is int: if a > b: return a else: return b ret = big_num(23, '4') print(ret)# 三元运算符
就是简单的 if else
a = 10 b = 20 c = a if a>b else b # a > b的话,c = a,否则 c = b print(c)答案:20
上面的也可以写成这样
def complit(a,b): return a if a>b else ba = 10b = 20print(complit(a,b))答案:20
# 2、关键字参数
def userinfo(name,age,area,telnum): print("姓名:%s age:%s area:%s telnum:%s" %(name,age,area,telnum)) userinfo(name="bob",age=18,area="henan",telnum=1234324354) userinfo(age=23,area='hanguo',name='simida',telnum=2343244)显示结果:
姓名:bob age:18 area:henan telnum:1234324354
姓名:simida age:23 area:hanguo telnum:2343244
# 练习题
# 函数:传入两个字符串参数,将两个参数拼接完成后形成的结果返回。def join_str(a,b): return a + b a = "bob" b = 'sb' ret = join_str(a=a,b=b) print(ret)显示结果: bobsb
# 3、混合参数
# 1、位置参数一定要在关键字参数的前面
# 2、不可以重复传参:重复传参也就是位置参数传入了一次,然后关键字参数又去传一次def userinfo(name,age,area,telnum): print("姓名:%s age:%s area:%s telnum:%s" %(name,age,area,telnum)) userinfo("juice",18,telnum=23425454,area="diqiu")显示结果:
姓名:juice age:18 area:diqiu telnum:23425454
4、形参角度分类
# 1、位置参数 :同实参的位置参数,都是从左到右,一一对应
# 2、默认参数 :在进行函数调用的时候,可以传值也可以不传值,传值的话就用传入的值,没有传的话就用默认的值
def userinfo(name,age,sex='男'): print('姓名:%s age:%s 性别:%s'%(name,age,sex)) userinfo("alex",18,sex='女') userinfo('bob',20)答案:
姓名:alex age:18 性别:女
姓名:bob age:20 性别:男
# 3、万能参数
# 定义一个函数:注意开放封闭原则def eat(a,b,c,d): print('请你吃:%s %s %s %s'%(a,b,c,d)) eat('鸡','鸭','鱼','肉')# 上面的eat的参数就写死了,如果需要扩展更多的食物就的修改函数里面的源代码,这就违反了开放封闭原则# *def eat(*args): food = '请你吃:' for i in range(len(args)): food += args[i] return food print(eat('鸡','鸭','鱼','肉','羊','牛肉'))# *args可以接收任意的位置参数,你在扩展的时候就不用动源代码,只需要在调用的时候传入参数即可
练习题
# 写一个函数,计算传入函数的所有的数字的和def sum_func(*args): sum = 0 for i in args: if type(i) is int: sum += i return sum ret = sum_func(2,3,7,8,3,7,30,"alex") print(ret)答案:60
# *args是接收所有的位置参数,哪来接收所有的关键字参数呢? **kwargsdef fun(**kwargs): print(kwargs) fun(name='bob',age=50) # 打印:{'name': 'bob', 'age': 50}# ** 会把所有的关键字参数转换成字典赋值给kwargs# 4、仅限关键字参数
# 形参里面的仅限关键字参数,比如下面的函数def func(*args,c,**kwargs): # c就是仅限关键字参数 print(args) print(c) print(kwargs) func(1,3,name='alex',c=5,age=18) # 调用的时候必须以关键字参数调用,也就是说必须写成 c=多少,调用的时候仅限关键字参数的位置要放在位置参数的后面# 答案:
(1, 3)
5
{'name': 'alex', 'age': 18}
5、参数的传入顺序
# 位置参数,*args, 仅限关键字参数,位置参数,**kwargs # 其中仅限关键字参数和位置参数可以调换位置
6、实参中的*,*的魔性用法
# * **在函数调用时,* 代表打散def func(*args,**kwargs): print(args) print(kwargs) # func([1,2],[3,4]) # 答案 ''' ([1, 2], [3, 4]) {} ''' # func(*[1,2],*[3,4]) # 相当于: func(1,2,3,4) # 结果: ''' (1, 2, 3, 4) {} ''' func(**{"a":"alex"},**{'b':'dt'}) # 相当于: func(a='alex',b='dt') # 结果: ''' () {'a': 'alex', 'b': 'dt'} ''' func(*[1,3],*[5,9],**{'name':'bob','age':18}) # 结果: ''' (1, 3, 5, 9) {'name': 'bob', 'age': 18} ''' func(2,4,*[1,3],*[5,9],**{'name':'bob','age':18}) # 结果: ''' (2, 4, 1, 3, 5, 9) {'name': 'bob', 'age': 18} '''
python的名称空间
# 名称空间分类
1、内置名称空间(builtins.py)
2、全局名称空间(当前py文件)
3、局部名称空间(函数,函数执行时才开辟)
# 加载顺序
内置名称空间 ----- 全局名称空间 ------ 局部名称空间(函数执行时)
作用域
分类:
1、全局作业域 (包括内置名称空间、全局名称空间)
2、局部作业域 (局部名称空间)
a = "bob" def func(): b = "jim" print(b) print(a) func()# 显示结果:"jim" "bob"
在这里: a就在全局作业域里面,b在局部作用域里面,局部作用域可以引用全局作用域的变量,但是不可以修改全局作用域的变量,全局作用域不可以使用局部作用域的变量。
比如下面的代码:
a = "bob" def func(): b = "jim" print(b) print(a) a += "sb" func()***这就会报错:UnboundLocalError: local variable 'a' referenced before assignment
为什么局部作用域不可以修改全局作用域的变量?
# 是因为局部作用域修改全局作用域的变量时,解释器就会认为在局部作用域里面已经
定义了该变量,所以就报错。
取值顺序
遵循的原则:就近原则,LEGB原则,如下图
函数的嵌套(高阶函数)
想要明白函数的嵌套,关键点:只要遇见了函数名+()就是函数的调用,如果没有就不是函数的调用:举例:
例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 func2(): print(2) def func3(): print(6) print(4) func3() print(8) print(3) func2() print(5)# 显示结果:3 2 4 6 8 5
globals() local()
# globals() local()都是字典
globals(): 以字典的形式返回全局作用域所有的变量对应关系
local():以字典的形式返回当前作用域的变量的对应关系
def func1():
age = 35
print(locals())
print(globals())
func1()显示结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000024DF527F588>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'F:/python_project/python_22/day10/s2 global local.py', '__cached__': None, 'name': 'alex', 'func1': <function func1 at 0x0000024DF53373A8>}
{'age': 35}
函数补充
当默认参数是个可变参数时,调用的时候不传值的话,他们共用的是默认参数开辟的内存所在的内存地址
补充1:
def func1(a,b=[]): b.append(a) return b ret1 = func1(20) print(ret1) ret2 = func1(10) print(ret2)# 显示结果:[20,] [20,10]
补充2:
def func1(a,b=[]): b.append(a) return b ret1 = func1(20) ret2 = func1(10) print(ret1) print(ret2)# 显示结果: [20,10] [20,10]
补充3:
def func1(a,list=[]): list.append(a) return list ret1 = func1(20) print(ret1) ret2 = func1(10,[]) print(ret2)# 显示结果: [20,] [10,]
补充4:
def func1(a,list = []): list.append(a) return list ret1 = func1(20) ret2 = func1(10,[]) ret3 = func1(100) print(ret1) print(ret2) print(ret3)# 显示结果: [20,100] [10,] [20,100]
总结:通过几个补充的例子,知道了默认值是可变数据类型时,要特别注意
补充5
count = 1 def func(): count += 1 # 局部作用域只能引用全局作用域的变量,而不能修改 print(count) func()# 显示结果:会报错
UnboundLocalError: local variable 'count' referenced before assignment
补充6:在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题。应该是在使用前先定义。
count = 1 def func(): print(count) # 解释器会以为你是先引用后定义 count = 2 func()# 显示结果:
UnboundLocalError: local variable 'count' referenced before assignment
关键字global nonlocal
global:
# 有些时候就想在局部作用域里面改全局作用域里面的变量怎么办呢?
name = 'alex' def func(): name = 'bob' print(name) func() print(name)# 显示结果: bob alexname = 'alex' def func(): global name name = 'bob' print(name) func() print(name)# 显示结果: 'bob' 'bob'# global里面定义的变量,如果函数没有执行的话,全局是没有这个变量的,会报错def func(): global name name = 'alex' print(name) print(name) func()# 显示结果:NameError: name 'name' is not defined小结:global可以对全局变量进行引用和修改
nonlocal:
# nonlocal局部作用域对父级作用域的变量进行引用和修改
def func(): name = 'alex' def inner(): nonlocal name name = 'bob' inner() print(name) func() # 显示结果: 'bob'# 显示结果: 'bob'# 小结:
1、nonlocal不能更改全局变量
2、局部作用域对父级作用域的变量进行引用和修改
----------------------- end -------------------------