python函数
一、函数初识
-
函数的定义和调用: 对功能进行定义和封装,方便调用
基本格式:
def 函数名(形参):
函数体(代码块)
函数名(实参)
-
函数名: 函数名的命名规则和变量是一样的
定义一个简单的函数并调用它:
1 def app(): 2 print("这只是在构建最基本的函数格式") 3 print("函数的功能并不只是打印内容") 4 print("函数的作用是封装功能,里面什么都能写") 5 6 app()
-
函数的返回值:
return 执行完函数之后. 我们可以使用return来返回结果.当函数执行到return之后,结束此函数,不在继续执行 return 可以返回多个值,用元组表示
1 def app(): 2 print("这只是在构建最基本的函数格式") 3 print("函数的功能并不只是打印内容") 4 print("函数的作用是封装功能,里面什么都能写") 5 return '基本格式', '封装功能' 6 print(app())
-
关于返回值:
如果return什么都不写 或者 干脆不写return .那么返回的就是None
如果return后面写了一个值. 则调用者可以接收一个结果
如果return后面写了多个结果, 则调用者可以接收一个tuple, 调用者可以直接解构成多个变量
-
函数的参数: 函数在调用的时候指定具体的一个变量的值. 就是参数.
形参:
位置参数: 按照位置顺序给函数创建参数
1 def yue(fangshi, age): # 形参 2 print("打开手机") 3 print("打开%s" % fangshi) 4 print("找一个漂亮的妹子") 5 print("年龄最好是%s" % age) 6 print("出来约一约") 7 8 yue("探探", 38) 9 yue("陌陌", 26)
默认值参数: 指定参数的值,如果传参是不输入值,则使用默认值
1 def regist(id, name, sex="男"): 2 print("录入学生信息:id是%s, 名字是%s, 性别是:%s" % (id, name, sex)) 3 4 regist(1, "大阳哥") 5 regist(2, "徐卫星") 6 regist(3, "毛尖妹妹", "女")
位置参数和默认值参数混合使用: 可以把上面两种参数混合着使用. 也就是说在调用函数的时候即可以给出位置参数, 也可 以指定参数的默认值.
实参:
位置参数: 按照位置给形参赋值
关键字参数: 按照名称给形参赋值
混合参数: 先用位置参数, 再用关键字参数
1 def gn(name, age, address, id, sex, hobby): 2 print("人的名字叫%s, 年龄:%s, 地址:%s, id是:%s, 性别:%s, 爱好是:%s" % (name, age, address, id, sex, hobby)) 3 gn("太白", 58, "保定", 1, "不详", "女") # 位置参数 4 gn(id=1, name="太白", address="保定", hobby="女", age=58, sex="不详") # 关键字(形参)参数 5 gn("太白", 58, "保定", id="3", sex="女", hobby="不详")
二、函数参数,命名空间和作用域
-
函数传参 - 动态传参
*args 动态传参 位置传参
def chi(*food): print("我要吃", food) chi("包子", '馒头', '米饭', '小龙虾', '黄焖鸡', '酸菜鱼')
示例:传入任意整数,求所有数的和
def num(*digit): sum = 0 for i in digit: sum = sum + i return sum print(num(1,2,3,4,5,6,7))
**kwargs 动态传参 关键字传参
def app(**games): print(games) app(free_game ='消消乐', dongzuo_game = "格斗之王", jingji_game = "王者荣耀", yizhi_game = '数独')
当*args 和 **kwargs一起使用时,什么东西都能传入
def func(*args,**kwargs): print(args) print(kwargs) func('哈士奇', '金毛', '萨摩', name='y',age=22,sex='nan')
参数接收顺序: 位置参数 , *args , 默认值参数 , **kwargs
-
函数的命名空间和作用域
-
命名空间
-
内置命名空间: 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内 置命名空间
全局命名空间: 我们直接在py⽂件中, 函数外声明的变量都属于全局命名空间
局部命名空间: 在函数中声明的变量会放在局部命名空间
加载顺序: 内置命名空间 , 全局命名空间 , 局部命名空间
取值顺序: 局部命名空间 , 全局命名空间 , 内置命名空间
-
-
作用域
-
全局作用域: 包含内置命名空间和全局命名空间. 在整个文件的任何位置都可以使用(遵循 从上到下逐行执行).
局部作用域: 在函数内部可以使用.
作用域命名空间:
全局作用域: 内置命名空间 + 全局命名空间
局部作用域: 局部命名空间
globals() 查看全局作用域中的名字
locals() 查看局部作用域中的名字
a = 10 def func(): a = 40 b = 20 def abc(): print("哈哈") print(a, b) # 这⾥使⽤的是局部作⽤域 print(globals()) # 打印全局作⽤域中的内容 print(locals()) # 打印局部作⽤域中的内容 func()
-
global 和 nonlocal
- global 把全局变量拿到局部来用
- nonlocal 把离他最近的一层的变量拿过来.不会找全局
global 使用示例
1 a = 100 2 def func(): 3 global a # 加了个global表示不再局部创建这个变量了. 而是直接使用全局的a 4 a = 28 5 print(a) 6 func() 7 print(a)
nonlocal 使用示例
1 a = 10 2 def func1(): 3 a = 20 4 def func2(): 5 nonlocal a 6 a = 30 7 print(a) 8 func2() 9 print(a) 10 func1()
三、函数名的应用(高阶函数),闭包,迭代器,生成器
-
函数可以像变量一样使用
1.函数名可以赋值给其他变量
2.函数名可以当做函数的参数
3.函数名可以作为函数的返回值
4.函数名可以作为list元素
赋值:
1 def func(): 2 print("呵呵") 3 print(func) 4 a = func # 把函数当成⼀个变量赋值给另⼀个变量 5 a() # 函数调⽤ func()
做list元素:
1 def func1(): 2 print("呵呵") 3 def func2(): 4 print("呵呵") 5 def func3(): 6 print("呵呵") 7 def func4(): 8 print("呵呵") 9 lst = [func1, func2, func3,func4] 10 for i in lst: 11 i()
做返回值:
1 def func_1(): 2 print("这里是函数1") 3 def func_2(): 4 print("这里是函数2") 5 print("这里是函数1") 6 return func_2 7 fn = func_1() # 执行函数1. 函数1返回的是函数2, 这时fn指向的就是上面函数2 8 fn() # 执行上面返回的函数
-
闭包
闭包就是内层函数, 对外层函数(非全局)的变量的引用. 叫闭包
1 def func1(): 2 name = "alex" 3 def func2(): 4 print(name) # 闭包 5 func2() 6 func1()
我们可以使用__closure__来检测函数是否是闭包. 使用函数名.__closure__返回cell就是 闭包. 返回None就不是闭包
1 def func1(): 2 name = "alex" 3 def func2(): 4 print(name) # 闭包 5 func2() 6 print(func2.__closure__) # (<cell at 0x10c2e20a8: str object at0x10c3fc650>,) 7 func1()
闭包的特征:
常驻内存
安全
-
迭代器
可迭代对象:str ,list,dict,tuple,set,range iterable(可迭代对象) 内部包含 __iter__() 函数
迭代器:文件句柄 iterator(迭代器) 内部包含__iter__() 和 __next__() 函数
迭代器示例:
1 lst = ['假','装','我','是','迭','代','器'] 2 3 f = lst.__iter__() 4 while 1: 5 try: 6 name = f.__next__() 7 print(name) 8 except StopIteration: 9 break
- 迭代器特征:
- 节省内存
- 惰性机制
- 不能反复,只能向下执行
生成器
- 生成器实质就是迭代器
- 获取生成器的方式:
- 通过生成器函数
- 通过推导式实现生成器
- 通过数据转换实现生成器
获取生成器函数 __next__():
1 def func(): 2 print('假装我是一个功能') 3 yield '然而并不是' 4 print('假装我是小蝌蚪') 5 yield '你看不见我' 6 print('假装我是一阵风') 7 yield '无影无形' 8 9 s = func() 10 print(s.__next__()) 11 print(s.__next__()) 12 print(s.__next__())
节省内存的方法:
1 def eggs(): 2 i = 1 3 while i < 101: 4 yield '鸡蛋%s' % i 5 i += 1 6 s = eggs() 7 print(s.__next__()) 8 print(s.__next__()) 9 print(s.__next__()) 10 print(s.__next__())
获取生成器函数 send():
1 def eat(): 2 print("我吃什么啊") 3 a = yield "馒头" 4 print("a=",a) 5 b = yield "⼤饼" 6 print("b=",b) 7 c = yield "⾲菜盒⼦" 8 print("c=",c) 9 yield "GAME OVER" 10 gen = eat() # 获取⽣成器 11 ret1 = gen.__next__() 12 print(ret1) 13 ret2 = gen.send("胡辣汤") 14 print(ret2) 15 ret3 = gen.send("狗粮") 16 print(ret3) 17 ret4 = gen.send("猫粮") 18 print(ret4)
列表推导式:
[结果 for 变量 in 可迭代对象 if 条件]
1 # 获取1-100内能被3整除的数 2 lst = [i for i in range(1,101) if i % 3 == 0] 3 print(lst)
1 # 寻找名字中带有两个e的人的名字 2 names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' ,'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']] 3 lst = [a for i in names for a in i if a.count('e') == 2] 4 print(lst)
字典推导式:
{结果 for 变量 in 可迭代对象 if 条件} 结果是键值对=》key:value
1 # 字典推导式 2 3 list1 = ['假', '装', '我', '是', '一', '阵', '风'] 4 list2 = ['你','看','我','是','6','个', '字'] 5 6 dic = {list1[i]:list2[i] for i in range(len(list1))} 7 print(dic)
集合推导式:
{结果 for 变量 in 可迭代对象 if 条件} 结果是 key
1 lst = [1, -1, 8, -8, 12] 2 # 绝对值去重 3 s = {abs(i) for i in lst} 4 print(s)
生成器表达式和列表推导式的区别:
1.列表推导式比较耗内存. 一次性加载. 生成器表达式几乎不占用内存. 使用的时候才分 配和使用内存
2.得到的值不一样. 列表推导式得到的是一个列表. 生成器表达式获取的是一个生成器