函数的作用
函数可以让编程逻辑结构化以及模块化
无论是C、C++,Java还是Python,函数是必不可少的知识点,也是很重要的知识点,函数是完成一个功能的代码块,使用函数可以使逻辑结构变得更加清晰以及程序模块化设计
先来看看Python函数相关知识
1 def test(x): 2 """我是用来描述这个函数的""" 3 x += 1 4 return x 5 6 # def : 定义函数的关键字 7 # test: 函数名 8 # (): 里面定义形参 9 # """ """: 用来描述这个函数的功能以及所传函数,返回值, 10 # x+= 1: 函数执行的代码块 11 # return :定义返回值
函数的的运行:函数名() 只有加上这个括号才是运行这个函数
函数运行的结束
当函数执行遇到return,后面所有的代码都是无效的,都不会执行
def test(): print('我会打印') return print('我不会被打印') test() """ 我会打印 """
函数参数:
- 形参:只在函数内部有效
- 实参:
- 位置参数和关键字参数
- 默认参数
- 参数组
__author__ = "Tang" # 形参:x y z def test(x,y,z): print(x) print(y) print(z) test(1,2,3) # 实参:1,2,3 # 位置参数 一一对应 def test(x,y,z): print(x) print(y) print(z) test(1,2,3) # # test(1,2) # 缺一不可 报错 # test(1,2,3,4) # 多一不可 报错 # 关键字参数 def test(x,y,z): print(x) # 2 print(y) # 1 print(z) # 3 test(y=1,x=2,z=3) # 位置参数 & 关键字参数 混搭 # 位置参数一定要在关键字的左边 def test(x,y,z): print(x) # 2 print(y) # 1 print(z) # 3 # test(1,3,y=2) # 报错 位置参数必须一一对应 test(1,y=3,z=2) # test(1,3,z=2,y=3) # 报错,传入参数比形参多 没有覆盖一说 # x,z 为默认参数 def test(x,y=1,z=3): print(x,y,z) test(10) # 10 1 3默认参数不传 使用默认的 test(10,20,30) # 10 20 30 如果传了就覆盖 # 不定参数 # 参数组: * 列表 元组, **字典 键值对 # 第一种 def test(x,*args): print(x) # 1 print(args) # (2, 3, 4, 5) print(*args) # 2 3 4 5 注意:这里没有换行 test(1,2,3,4,5) # 第二种 *() def test(x,*args): print(x) # 1 print(args) # ((2, 3, 4, 5, 6) print(*args) # 2 3 4 5 6 注意:这里没有换行 test(1,2,3,*(4,5,6)) # 第三种 () def test(x,*args): print(x) # 1 print(args) # ((2, 3, (4, 5, 6)) print(*args) # 2 3 (4, 5, 6) 注意:这里没有换行 test(1,2,3,(4,5,6)) # 第四种 [] def test(x,*args): print(x) # 1 print(args) # (2, 3, [4, 5, 6]) print(*args) # 2 3 [4, 5, 6] 注意:这里没有换行 test(1,2,3,[4,5,6]) # 第五种 *[] def test(x,*args): print(x) # 1 print(args) # ((2, 3, 4, 5, 6) print(*args) # 2 3 4 5 6 注意:这里没有换行 test(1,2,3,*[4,5,6]) # **kwargs 字典 键值对 # 第一种 def test(x,**kwargs): print(x) # 1 print(kwargs) # {'y': 2, 'z': 3} # print(**kwargs) # 报错 test(1,y=2,z=3) # 第二种 def test(x,**kwargs): print(x) # 1 print(kwargs) # {'y': 2, 'z': 3} # print(**kwargs) # 报错 # test(1,{"y":2,"z":3}) # 报错 test(1,**{"y":2,"z":3})
函数里面可以调用函数
__author__ = "Tang" def test1(): print('我是test1') def test2(): print('我是test2') test1() test2() """ 我是test2 我是test1 """
全局变量与局部变量
- 全局变量一般都是大写 ,在整个程序中都可以被访问
- 局部变量,定义在代码块中,for循环,函数等
__author__ = "Tang" name = "我是全局变量" # def test(): name = "我是局部变量" print(name) # 我是局部变量 test() print(name) # 我是全局变量
以上例子可以看到,当局部变量和全局变量都为同一个变量名的时候,在代码块里面,首先先找代码块中的变量也就是局部变量,当代码块中找不到该变量,就找全局变量
name = "我是全局变量" # def test(): print(name) # 我是全局变量 test() print(name) # 我是全局变量
在代码块中修改全局变量需要用到关键字 global
name = "我是全局变量" # def test(): global name name = "我是全局变量,我被修改啦" print(name) # 我是全局变量,我被修改啦 test() print(name) # 我是全局变量,我被修改啦
请注意看我哦!
name = "我是全局变量" def test(): global name print(name) # 我是全局变量 name = "我是全局变量,我被修改啦" print(name) # 我是全局变量,我被修改啦 test() print(name) # 我是全局变量,我被修改啦
总结:当找不到代码块中的变量,就会到上一级中找该变量。当看到global 关键字,就要想到要重修赋值全局变量。如果没有global关键字,只能读取全局变量,无法重新赋值全局变量的值。
下面请注意
当全局变量为可变数据类型的时候,可在代码块中对全局变量进行修改(增,删,改),但是不能对全局变量进行重新赋值,赋值的只是局部变量,除非用global 关键字进行声明为全局变量,此时才是赋值给全局变量
# 第六种 列表添加 NAME = ["tang","lao"] def test(): NAME.append('er') print(NAME) # ['tang', 'lao', 'er'] test() print(NAME) # ['tang', 'lao', 'er'] # 第七种 列表删除 NAME = ["tang","lao",'er'] def test(): NAME.remove('er') print(NAME) # ['tang', 'lao'] test() print(NAME) # ['tang', 'lao'] # 第八种 列表修改 NAME = ["tang","lao",'er'] def test(): NAME[0] = "chen" print(NAME) # ['chen', 'lao', 'er'] test() print(NAME) # ['chen', 'lao', 'er'] # 第九种 字典 修改 NAME = {"name":"tang","age":18} def test(): NAME["name"] = "chen" print(NAME) # {'name': 'chen', 'age': 18} test() print(NAME) # {'name': 'chen', 'age': 18} # 第九种 字典 添加 NAME = {"name":"tang","age":18} def test(): NAME["hobby"] = "girl" print(NAME) # {'name': 'tang', 'age': 18, 'hobby': 'girl'} test() print(NAME) # {'name': 'tang', 'age': 18, 'hobby': 'girl'} # 第九种 字典 删除 NAME = {"name":"tang","age":18} def test(): del NAME["name"] print(NAME) # {'age': 18} test() print(NAME) # {'age': 18}
# 没有global 赋值 NAME = {"name":"tang","age":18} def test(): NAME = {'a':1,'b':2} print(NAME) # {'a': 1, 'b': 2} test() print(NAME) # {'name': 'tang', 'age': 18} # 有global 赋值 NAME = {"name":"tang","age":18} def test(): global NAME NAME = {'a':1,'b':2} print(NAME) # {'a': 1, 'b': 2} test() print(NAME) # {'a': 1, 'b': 2}
一个错误的特例
__author__ = "Tang" # 错误的例子 报错 # NAME = ['tang','lao','er'] # def test(): # NAME = "chen" # global NAME # print(NAME) # test() # print(NAME) # 改正 NAME = "tang" def test(): global NAME # 我是声明 我要在 NAME 其他操作的前面 NAME = "chen" print(NAME) # chen test() print(NAME) # chen
总结:声明要在其他操作的前面,不然会报错。。。。。。
为了防止错误,全局变量大写,局部变量小写,可以防止编程出现没必要的错误
函数嵌套
1 __author__ = "Tang" 2 3 # 函数嵌套 4 NAME = "全局" 5 def yeye(): 6 name = "爷爷级别" 7 print(name) 8 def fu(): 9 name = "父级别" 10 print(name) 11 def zi(): 12 name = "子级别" 13 print(name) 14 def sunzi(): 15 name = "孙子级别" 16 print(name) 17 sunzi() 18 zi() 19 fu() 20 yeye() 21 print(NAME) 22 23 """ 24 爷爷级别 25 父级别 26 子级别 27 孙子级别 28 全局 29 """
再来一个,请仔细看
name = "A" def test(): name = "B" def test_test(): global name name = "C" test_test() print(name) # B print(name) # A test() print(name) # C
关键字 nonlocal 声明上一级的变量
name = "A" def test(): name = "B" def test_test(): nonlocal name # nonlocal,指定上一级变量 name = "C" test_test() print(name) # C print(name) # A test() print(name) # A
nonlocal 只能使用于两级或多级函数嵌套,一级嵌套会导致程序报错,下面请看一个错误的示例
name = "A" def test(): nonlocal name # 报错 name = "C" print(name) print(name) test() print(name)
函数声明与调用的顺序
函数即变量,调用函数前需先声明
# 第一种情况 def foo(): print("foo") bar() def bar(): print("bar") foo()
下面看一个错误的例子
# 第二种情况 报错的例子 def foo(): print("foo") bar() foo() def bar(): print("bar")
函数递归
- 必须有一个明确的结束条件(if 判断)return结束
- 每次进入更深一层递归时,问题规模相比上一次递归都应有所减少
1 __author__ = "Tang" 2 3 def calc(n): 4 print(n) 5 if int(n / 2) ==0: 6 return n 7 res = calc(int(n/2)) 8 print("****",res) 9 return res 10 n = calc(10) 11 print(n) 12 """ 13 10 14 5 15 2 16 1 17 **** 1 18 **** 1 19 **** 1 20 1 21 """
递归代码练习:一个快速排序的例子
1 # coding:utf-8 2 def quick_sort(alist, first, last): 3 """快速排序""" 4 if first >= last: 5 return 6 mid_value = alist[first] 7 low = first 8 high = last 9 while low < high: 10 # high 左移 11 while low < high and alist[high] >= mid_value: 12 high -= 1 13 alist[low] = alist[high] 14 15 while low < high and alist[low] < mid_value: 16 low += 1 17 alist[high] = alist[low] 18 # 循环退出时,满足条件low==high 19 alist[low] = mid_value 20 21 # 对low左边的列表执行快速排序 22 quick_sort(alist, first, low-1) 23 24 # 对low右边的列表排序 25 quick_sort(alist, low+1, last) 26 27 28 if __name__ == "__main__": 29 li = [54, 26, 93, 17, 77, 31, 44, 55, 20] 30 print(li) 31 quick_sort(li, 0, len(li)-1) 32 print(li)
斐波那契数列
__author__ = "Tang" # 斐波那契数列 a = 0 b = 1 while b < 1000: print(b,end=" ") a,b = b, a+b # 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 # 生成前20项 lis =[] for i in range(20): if i ==0 or i ==1:# 第1,2项 都为1 lis.append(1) else: lis.append(lis[i-2]+lis[i-1])# 从第3项开始每项值为前两项值之和 print(lis) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765] # 递归实现 li = [] def test(a, b): if a > 1000 or b > 1000: return li.append(a) li.append(b) a = a + b b = a + b test(a, b) test(1, 1) print(li) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
函数作用域相关练习
1 __author__ = "Tang" 2 3 """函数的作用域相关练习""" 4 5 """ 6 寻找变量的顺序:当前函数里面寻找,如果找不到就往上一层函数找,实在找不到就找全局变量 7 函数的调用:函数名+ () 函数名即变量,只要取得函数地址就可以 8 """ 9 10 # 第一种 11 def foo(): 12 print("我是foo") 13 def bar(): 14 print("我是bar") 15 bar() 16 foo() 17 # bar() # 报错 不可以直接调用 记住:要想执行里面的,就要先执行外面的,想象盒子里面包含盒子,外面的盒子不拿掉,里面的也拿不出来 18 """ 19 我是foo 20 我是bar 21 """ 22 23 # 第二种 24 def foo(): 25 print("我是foo") 26 def bar(): 27 print("我是bar") 28 return bar 29 test = foo() 30 test() # 可以调用 test拿到bar函数的地址 31 """ 32 我是foo 33 我是bar 34 """ 35 36 # 第三种 37 def test(): 38 print("我是test") 39 print(test()) # 没有没有返回值 默认为None 40 """ 41 我是test 42 None 43 """ 44 45 # 第四种 46 def test(): 47 print("我是test") 48 return 10 49 print(test()) 50 """ 51 我是test 52 10 53 """ 54 55 # 第五种 56 name = "tang" 57 def foo(): 58 name = "chen" 59 def bar(): 60 name = "li" 61 print(name) 62 return bar 63 a = foo() 64 print(a) 65 a() 66 """ 67 <function foo.<locals>.bar at 0x02FE0B28> 68 li 69 """ 70 71 # 第六种 72 name = "tang" 73 def foo(): 74 name = "chen" 75 def bar(): 76 print(name) 77 return bar 78 a = foo() 79 print(a) 80 a() 81 """ 82 <function foo.<locals>.bar at 0x00830B70> 83 chen 84 """ 85 86 # 第七种 87 name = "tang" 88 def foo(): 89 name = "chen" 90 def bar(): 91 print(name) 92 return bar 93 foo()() 94 """ 95 chen 96 """
匿名函数 lambda
lambda x : x+1 一个简单的匿名函数
__author__ = "Tang" def test(x): return x + 1 res = test(10) print(res) # 11 # 匿名函数实现上面函数 func = lambda x:x+1 print(func(10)) # 11
下面通过一些简单的例子来加深匿名函数的理解
# 第一个 name = "tang" def change_name(x): return x +"_sb" res = change_name(name) print(res) # tang_sb res = lambda x:name+"_sb" print(res(name)) # tang_sb print(res("tang")) # tang_sb res = lambda x:x+"_sb" print(res(name)) # tang_sb print(res("tang")) # tang_sb # 第二个 传多个参数 func = lambda x,y,z:x+y+z print(func(1,2,3)) # 6 # 第三个 name1 = "tang" name2 = "lao" name3 = "er" x = lambda name1,name2,name3:"".join([name1,name2,name3]) print(x(name1,name2,name3)) # tanglaoer