python——函数
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
一、语法定义
def say_hi():
print("hello world")
say_hi() # 调用函数
二、函数的参数
def calc(x, y):
res = x**y
return res # 返回函数执行结果
c = calc(2, 3) # 结果赋值给c变量
print(c)
形参
只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。
实参
可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值。
默认参数
看如下代码:
def stu_register(name,age,country,course):
print("----注册学生信息------")
print("姓名:",name)
print("age:",age)
print("国籍:",country)
print("课程:",course)
stu_register("王山炮",22,"CN","python_devops")
stu_register("张叫春",21,"CN","linux")
stu_register("刘老根",25,"CN","linux")
发现 country 这个参数 基本都 是"CN", 就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是 中国, 这就是通过默认参数实现的,把country变成默认参数非常简单:
def stu_register(name,age,course,country="CN"):
这样,这个参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值。
另外,你可能注意到了,在把country变成默认参数后,我同时把它的位置移到了最后面,为什么呢?
这就要谈到 “关键参数”了。
关键参数
正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),但记住一个要求就是,关键参数必须放在位置参数(以位置顺序确定对应关系的参数)之后。
def stu_register(name, age, course='PY' ,country='CN'):
print("----注册学生信息------")
print("姓名:", name)
print("age:", age)
print("国籍:", country)
print("课程:", course)
调用时
可以这样写:
stu_register("王山炮",course='PY', age=22,country='JP' )
但不能这样:
stu_register("王山炮",course='PY',22,country='JP' )
关键参数不可以放在未知参数之前,否则会报错。
也不能这样:
stu_register("王山炮",22,age=25,country='JP' )
相当于给age两次赋值,会报错。
非固定参数
若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数:*args,**kwargs。
def stu_register(name, age, *args): # *args 会把多传入的参数变成一个元组形式 print(name, age, args) stu_register("Henry", 22, "IT", "2018-05-08") 输出: Henry 22 ('IT', '2018-05-08')
def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式 print(name,age,args,kwargs) stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong") 输出: Jack 32 ('CN', 'Python') {'sex': 'Male', 'province': 'ShanDong'} # 后面这个('CN', 'Python')就是args,{'sex': 'Male', 'province': 'ShanDong'}就是kwargs
返回值
函数外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回。
def stu_register(name, age, course='PY', country='CN'): print("----注册学生信息------") print("姓名:", name) print("age:", age) print("国籍:", country) print("课程:", course) if age > 22: return False else: return True registriation_status = stu_register("王山炮",22,course="PY全栈开发",country='JP') if registriation_status: print("注册成功") else: print("too old to be a student.")
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,因此,可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
全局与局部变量
- 在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
- 全局变量作用域是整个程序,局部变量作用域是定义该变量的函数。
- 当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用;在其它地方全局变量起作用。
- 可以在函数里面可以调用外面的全局变量,但不能修改全局变量。
- 两个同级的独立的函数中相同名字的变量是互不相干的,不会存在相互调用等现象。
name = "Alex" def change_name(name): print("before change:", name) name = "Jack" print("after change", name) change_name(name) print("在外面看看name改了么?",name) 输出: before change: Alex after change Jack 在外面看看name改了么? Alex
在程序运行完后,name的值依然没有改变,那么有没有办法让它改变呢??
当然有啦!改变它的作用域就可以了。
作用域
在python中,一个函数就是一个作用域,函数定义完成或作用域就已经生成。
如何在函数里修改全局变量:
name = "Alex" def change_name(): global name # 将name改为全局变量 print("before change:", name) name = "Jack" print("after change", name) change_name() print("在外面看看name改了么?", name) 输出: before change: Alex after change Jack 在外面看看name改了么? Jack
在函数内部将name定义为全局变量,这样就可以改变它的值了。
其他作用域示例:
names = ["luara", "jason", "henry"] def change_name(): names = ["luara", "jason"] print("after change:", names) change_name() print("outer:", names) 输出: after change: ['luara', 'jason'] outer: ['luara', 'jason', 'henry']
names = ["luara", "jason", "henry"] def change_name(): del names[2] print("after change:", names) change_name() print("outer:", names) 输出: after change: ['luara', 'jason'] outer: ['luara', 'jason']
从以上两个程序运行结果发现,第二个程序的names被改变了,为什么呢?
原因是:与之前讲的深浅copy一个道理,一个列表就有一个自己的内存地址,而其里面的元素又有它们自己单独的内存地址,在函数内对列表整体进行修改时,不会影响外层的names,但对列表内的元素进行操作时,便会影响外层的names。类似的还有字典、类、集合等。
age = 19 def func1(): age = 73 def func2(): print("func2:", age) return func2 # 返回一个函数名 val = func1() # val获取到了func2的内存地址 print(val) val() # 此时相当于执行func2() 输出: <function func1.<locals>.func2 at 0x0000000001E59AE8> # 打印了func2的内存地址 func2: 73
嵌套函数
在一个函数体内用“def”定义了另外一个函数就叫嵌套函数。
def func1(): print("alex") def func2(): print("eric") func1() 输出: alex
发现内层的函数func2没有执行,因为程序没有调用它,一个函数如果没有被调用,它是永远不会执行的。
def func1(): print("alex") def func2(): print("eric") func2() # 调用func2 func1() # 调用func1 输出: alex eric
age = 19 def func1(): age = 73 print("func1:", age) def func2(): print("func2:", age) func2() func1() 输出: 73 73
age = 19 def func1(): def func2(): print("func2:", age) age = 73 func2() func1() 输出: func2: 73
在函数执行过程中,如果在自己内部没有找到age,它就会去它的外面一层找,若找到了就打印,若没有找到,就会接着再往外寻找,直到找到为止。
所以说,嵌套函数是从内到外,逐层寻找。
匿名函数
不需要显示的指定函数名的函数就叫匿名函数。
语法:
lambda 参数:表达式
如下代码:
def calc(x, y): return x * y print(calc(2, 3))
可以用匿名函数改写为:
calc = lambda x,y: x * y print(calc(2, 3))
匿名函数三元运算:
calc = lambda x, y: x if x > y else y print(calc(3, 1))
匿名函数主要与其他函数搭配使用:
res = list(map(lambda x: x**2, [1, 2, 3, 4])) print(res) 输出: [1, 4, 9, 16]
高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就叫高阶函数。
def add(x, y, f): return f(x) + f(y) # 相当于abs(4) + abs(-9) res = add(4, -9, abs) print(res) 输出: 13
只需满足以下任意一个条件,即是高阶函数:
- 接收一个或多个函数名作为参数输入
- return 返回另外一个函数(返回值中包含函数名)
递归函数
如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归函数示例:n的阶乘,这是我认为最能直观理解递归执行过程的示例
def fact(n): if n == 1: return 1 # 当n=1时结束递归 return n * fact(n-1) res = fact(5) print(res)
函数执行过程:
在n=1之前,函数将一直被挂起,直到遇到结束条件,函数再一层一层返回。
传入一个数,只执行5次就结束:
def calc(n, count): print("n:{}, count:{}".format(n, count)) if count < 5: return calc(n/2, count+1) else: return n # 如果count>5 就返回当前的n值 res = calc(188, 0) print("程序结束时的n值:", res) 输出: n:188, count:0 n:94.0, count:1 n:47.0, count:2 n:23.5, count:3 n:11.75, count:4 n:5.875, count:5 程序结束时的n值: 5.875
递归特性:
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
堆栈扫盲http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
递归函数实际应用案例,二分查找:
# 使用二分法查找列表中的某个数据 li = [2, 3, 6, 44, 34, 78, 67, 77, 90, 345, 67, 39, 100, 104, 209, 56, 789, 290, 62] def find(li1, num): print(li1) n = int(len(li1)/2) # 列表长度折半 if n >= 1: # 列表元素大于1 if num < li1[n]: # 数字在列表左边 print("the number is in the left of the list") return find(li1[0:n], num) elif num > li1[n]: # 数字在列表右边 print("the number is in the right of the list") return find(li1[n+1:], num) elif num == li1[n]: print("find the number:", li1[n]) else: if num == li1[n]: print("find the number:", li1[n]) else: print("the number is not existed!") li.sort() # 列表元素排序 print(li) find_num = int(input("input the number you want to find:")) find(li, find_num)
内置函数
内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii