目录
第五章 函数
5.1 函数的概述
在python中定义函数的时候需要使用def关键字,依次写的函数的名称、函数参数、冒号、函数体,如果函数有返回值的话需要使用return关键字进行返回
5.2 函数的定义和调用函数
语法规则
def 函数名称([函数的参数]): #缩进 函数体 [return 函数的返回值]
#创建一个求绝对值的函数 def my_abs(x): if x >= 0: return x else: return -x print(my_abs(-99))
调用函数的时候使用函数的名称进行调用
总结:如果函数在执行过程中,一旦执行了return,函数就会把结果进行返回,那如果没有return,函数的返回值是None
>>> def my_abs(x): ... if x >= 0 : ... return x ... else: ... return -x ... >>> my_abs(-99) 99
函数在调用的过程中必须要注意的函数的参数类型和个数
>>> my_abs("a") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in my_abs TypeError: '>=' not supported between instances of 'str' and 'int' >>> my_abs(-99,99) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: my_abs() takes 1 positional argument but 2 were given
isinstance()
#创建一个求绝对值的函数 def my_abs(x): if not isinstance(x,(float,int)): raise TypeError("bad operand type") if x >= 0: return x else: return -x print(my_abs("a"))
函数也可以返回多个值
import math def move(x,y,step,angle): nx = x + step + math.sin(angle) ny = y + step + math.cos(angle) return nx,ny # print(move(100,100,60,math.pi/6)) x,y = move(100,100,60,math.pi/6) print(x,y)
函数可以返回多个值,但是返回的结果是一个元组类型
5.3 函数的分类
根据有无参数:有参函数 无参函数
根据有无返回值:有返回值函数 无返回值函数
定义者分类:系统自定义的函数(abs min max) 第三方定义的函数(公司、某个组织、个人自己定义)
5.4 函数的参数
函数的参数:位置参数、默认值参数、命名参数、可变参数、万能参数
#计算圆的周长 def get_circle_cal(r,pi): return 2*pi*r # r = eval(input("请输入圆的半径")) # cal = get_circle_cal(r,3.14) # print("半径是{}的圆的周长是{}".format(r,cal)) if __name__ == "__main__": r = eval(input("请输入圆的半径")) cal = get_circle_cal(r,3.14) print("半径是{}的圆的周长是{}".format(r,cal))
总结:python中代码的入口不是main函数
python是一门脚本语言,从上到下的顺序执行
main作用:写在main函数中的代码不会被导入到其他模块中
5.4.1 位置参数
def get_circle_cal(r,pi): return 2*pi*r def power(x): return x*x def power1(x,n): return x ** n
5.4.2 默认值参数
def power1(x,n=2): return x ** n print(power1(3,3)) print(power1(3))
注意:位置参数必须在前,默认值参数必须在后
如何这个函数有多个默认值参数,变化较小写在后面,变化较大的写在前面
def enroll(name,gender,age=18,city="重庆"): print("name",name) print("gender",gender) print("age",age) print("city",city) # enroll("张三","男") # enroll("李四","男",17) print(enroll("李四","男",17))
def add_list(L=[]): L.append("END") return L print(add_list([1,2,3,4])) print(add_list([1,2,3,4])) print(add_list([1,2,3,4])) print(add_list([1,2,3,4]))
def add_list(L=[]): L.append("END") return L print(add_list()) print(add_list()) print(add_list()) print(add_list()) print(add_list())
运行结果:
['END'] ['END', 'END'] ['END', 'END', 'END'] ['END', 'END', 'END', 'END'] ['END', 'END', 'END', 'END', 'END']
因为L指向的[] ---- 可变对象
注意:设置默认值参数的时候一定要指向一个不可变对象
不可变对象 ---- None
def add_list(L=None): if L is None: L = [] L.append("END") return L print(add_list()) print(add_list()) print(add_list()) print(add_list())
5.4.3 可变参数
可变参数是用*来表示的
可以传递实际的参数,或者可以不传递参数,可以传递0个、1个........ 任意个参数,底层是用元组的形式将参数进行封装起来
def calc(numbers): sum = 0 for i in numbers: sum = sum + i * i return sum print(calc([1,2,3,4,5])) print(calc((1,2,3,4,5)))
def calc(*numbers): sum = 0 for i in numbers: sum = sum + i * i return sum print(calc(1,2,3,4,5)) print(calc(1)) print(calc())
def calc(*numbers): sum = 0 for i in numbers: sum = sum + i * i return sum list = [1,2,3,4,5] print(calc(list[0],list[1],list[2],list[3],list[4])) print(calc(*list))
5.4.4 关键字参数
关键字参数也可以传递0个、1个或者任意个参数,它的底层是将参数封装成一个dict
def person(name,age,**kw): print("name:",name,"age:",age,"kw:",kw) person("张三",18) person("李四",20,city="重庆",gender="男")
dict = {"gender":"女","city":"北京"} person("王五",20,**dict)
5.4.5 命名关键字参数
def person(name,age,**kw): if "gender" in kw: pass elif "city" in kw: pass print("name:",name,"age:",age,"kw:",kw)
需求:只能传入gender和city这两个参数,其他参数不能传入
def person(name,age,*,gender,city): print("name:",name,"age:",age,"gender:",gender,"city:",city) # person("张三",20,job="XXX工程师") person("张三",20,gender="男",city="重庆")
命名关键字参数可以取默认值
def person(name,age,*,gender,city="重庆"): print("name:",name,"age:",age,"gender:",gender,"city:",city) person("张三",20,gender="男")
5.4.6 参数的组合
可以存在同一个函数中,但是一定有顺序
顺序:位置参数 默认值参数 可变参数 命名关键字参数 关键字参数
def f1(a,b,c=0,*args,**kw): print("a=",a,"b=",b,"c=",c,"args=",args,"kw=",kw) def f2(a,b,c=0,*,d,**kw): print("a=",a,"b=",b,"c=",c,"d=",d,"kw=",kw) f1(1,2,c=3) f1(1,2,3,"a","b") f1(1,2,3,"a",X=99) f2(1,2,3,d=99,x=88)
a= 1 b= 2 c= 3 args= () kw= {} a= 1 b= 2 c= 3 args= ('a', 'b') kw= {} a= 1 b= 2 c= 3 args= ('a',) kw= {'X': 99} a= 1 b= 2 c= 3 d= 99 kw= {'x': 88}
def f1(a,b,c=0,*args,**kw): print("a=",a,"b=",b,"c=",c,"args=",args,"kw=",kw) def f2(a,b,c=0,*,d,**kw): print("a=",a,"b=",b,"c=",c,"d=",d,"kw=",kw) # f1(1,2,c=3) # f1(1,2,3,"a","b") # f1(1,2,3,"a",X=99) # f2(1,2,3,d=99,x=88) args = (1,2,3,4) kw = {"d":99,"x":88} f1(*args,**kw) args1 = (1,2,3) kw1 = {"d":99,"x":88} f2(*args1,**kw1)
a= 1 b= 2 c= 3 args= (4,) kw= {'d': 99, 'x': 88} a= 1 b= 2 c= 3 d= 99 kw= {'x': 88}
5.5 局部变量和全局变量
全局变量:
在python中,定义在py文件中的变量称为全局变量
特点:代码运行的过程中始终有效(不会被垃圾回收机制回收,除非手动的回收)
name = "张三" #name就是全局变量 name = None
局部变量:
定义在函数中的变量称为局部变量,当函数被垃圾回收机制回收的时候,局部变量也会被回收
局部变量的作用域仅限于函数的内部,在函数的外部是不能访问的,会报错
name = "张三" #name就是全局变量 # name = None age = 18 def show(msg): gender = "男" #局部变量 print(msg) print(gender) print(name) #在函数的内部是可以访问全局变量的 print(age) # print(show("哈哈哈哈哈哈哈")) show("哈哈哈哈") # print(gender)
总结:函数的外面不能访问函数内部定义的变量(局部变量)
反过来说,函数的内部是可以访问函数外的变量(全局变量),但是不能改变全局变量,如果非要去改变(操作)全局变量的话,需要借助global关键字
name = "张三" #name就是全局变量 # name = None age = 18 def show(msg): gender = "男" #局部变量 global age print(msg) print(gender) print(name) #在函数的内部是可以访问全局变量的 print(age) age += 1 print(age) # print(show("哈哈哈哈哈哈哈")) show("哈哈哈哈") # print(gender)
5.6 函数运行原理
为什么函数的内部不能去操作全局变量
函数是对象 ---- 对象存储在堆内存中
函数的调用的过程中,是一个压栈的过程,当函数调用完成之后,就会有弹栈的过程,弹栈之后就会被垃圾回收机制回收
5.7 值传递和引用传递
值传递:传递的是值
x,y之间是不冲突的,因为add(x,y)中的x和y是局部变量(形参),而后面输入的Input的x和y是实参,将实参传递给了形参
引用传递:传递的是对象
def info(fn,msg): fn() print(msg) def print_msg(): print("哈哈哈哈哈哈哈") print(print_msg) #打印的是函数在内存中存储的内存地址 print_msg指的是函数本身 print(print_msg()) #None 因为函数没有返回值
def info(fn,msg): fn() print(msg) def print_msg(): print("哈哈哈哈哈哈哈") # print(print_msg) #打印的是函数在内存中存储的内存地址 print_msg指的是函数本身 # print(print_msg()) #None 因为函数没有返回值 #引用传递 info(print_msg,"呵呵呵呵呵呵呵呵呵")
5.8 匿名函数 ---- lambda表达式
匿名函数:没有名字的函数,在python中是使用lambda这个表达式进行实现
function 函数名称(函数参数){ 函数体 代码块 return 返回值 } function (函数参数){ 函数体 代码块 return 返回值 }
def 函数的名称([函数的参数]): #缩进 代码块 函数体 return 函数的返回值 def ([函数的参数]): #缩进 代码块 函数体 return 函数的返回值 ------- 不支持的
匿名函数函数:
lambda 参数 :函数体 如果函数有返回值进行返回,如果没有就不用返回
def sum_abc(a,b,c): return a+b+c print(sum_abc(10,20,30)) sum_lambda = lambda a,b,c : a+b+c print(sum_lambda(10,20,30))
无参的匿名函数
lambda_a = lambda : 100 print(lambda_a()) print(lambda_a)
一个参数:
lambda_b = lambda num : num * 10 print(lambda_b(10))
多个参数:
sum_lambda = lambda a,b,c : a+b+c print(sum_lambda(10,20,30))
包含表达式:
lambda_c = lambda x : x if x % 2 == 0 else x + 1 print(lambda_c(6)) print(lambda_c(7))
总结:匿名函数是使用lambda表达式进行实现的,可以传入0个参数、1个参数、任意个参数,甚至可以包含表达式,但是函数返回值只有一个
lambda也可以作为一个参数进行传递
def sub_func(a,b,func): print("a=",a) print("b=",b) print("a-b=",func(a,b)) sub_func(100,1,lambda a,b : a - b ) # func = lambda a,b : a - b func(a,b)
lambda作为函数的返回值
def run_func(a,b): return lambda c : a+b+c return_func = run_func(1,1000) # return_func = lambda c : 1+1000+c print(return_func) print(return_func(100))
5.9 偏函数
在python中,有时候我们需要调用某个函数的时候,如果将该函数的某个参数固定成某个值,可以使用偏函数
python中functools模块中,有一个方法就是偏函数 partial()
import functools
functools.partial()
from functools import partial ------ 只导入partial
>>> int("1234") 1234 >>> help(int) Help on class int in module builtins: class int(object) | int([x]) -> integer | int(x, base=10) -> integer | | Convert a number or string to an integer, or return 0 if no arguments | are given. If x is a number, return x.__int__(). For floating point | numbers, this truncates towards zero. | >>> int("1234",base=8) 668 >>> int("1234",base=16) 4660 >>> def int2(x,base=2): ... return int(x,base) ... >>> int2("11001100") 204 >>> int2("0010") 2 >>> import functools >>> dir(functools) ['GenericAlias', 'RLock', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', '_CacheInfo', '_HashedSeq', '_NOT_FOUND', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_c3_merge', '_c3_mro', '_compose_mro', '_convert', '_find_impl', '_ge_from_gt', '_ge_from_le', '_ge_from_lt', '_gt_from_ge', '_gt_from_le', '_gt_from_lt', '_initial_missing', '_le_from_ge', '_le_from_gt', '_le_from_lt', '_lru_cache_wrapper', '_lt_from_ge', '_lt_from_gt', '_lt_from_le', '_make_key', '_unwrap_partial', 'cache', 'cached_property', 'cmp_to_key', 'get_cache_token', 'lru_cache', 'namedtuple', 'partial', 'partialmethod', 'recursive_repr', 'reduce', 'singledispatch', 'singledispatchmethod', 'total_ordering', 'update_wrapper', 'wraps'] >>> functools.partial(int,base=2) functools.partial(<class 'int'>, base=2) >>> int3 = functools.partial(int,base=2) >>> int3("11001100") 204
偏函数的作用但是将函数某个参数固定住(取一个默认值)
>>> int3("11001100",base=10) 11001100 >>> int3("11001100",base=8) 2359872 >>> int3("11001100",base=16) 285217024 >>> kw = {"base":10} >>> int3("1100",**kw) 1100
5.10 函数的递归
在函数的内部可以调用其他的函数,但是如果在函数的内部调用函数自己,就是函数的递归
前提条件:
1、函数自己调用自己
2、要有终止条件
需求1:求n!
n*(n-1)*(n-1)*.......*2*1
函数+循环
def fact(n): sum = 1 for i in range(1,n+1): # sum = sum * i sum *= i return sum print(fact(5))
def fact_recursion(n): if n == 1: return 1 return n*fact_recursion(n-1) print(fact_recursion(5))
fact_recursion(5) 5 * fact_recursion(5-1) 5 * 4 * fact_recursion(4-1) 5 * 4 * 3 * fact_recursion(3-1) 5 * 4 * 3 * 2 * fact_recursion(2-1) 5 * 4 * 3 * 2 * 1
需求2:求斐波那契数列的第n项
0 1 1 2 3 5 8 13 21 .........
def fabonaci(n): first,second = 0,1 for i in range(2,n+1): first,second = second,first+second return first print(fabonaci(5)) print(fabonaci(6)) print(fabonaci(7)) ls = [] def fabonaci(n): first,second = 0,1 for i in range(1,n+1): ls.append(first) first,second = second,first+second return ls print(fabonaci(5))
def fabonaci_recursion(n): if n == 1: return 0 elif n == 2: return 1 return fabonaci_recursion(n-1)+fabonaci_recursion(n-2) print(fabonaci_recursion(5)) print(fabonaci_recursion(6)) print(fabonaci_recursion(7))
所有的递归都可以用循环来实现,递归是一种特殊的循环
print(fact_recursion(1000))
递归会存在栈溢出的问题 -------- 尾递归 对递归方式进行了优化
尾递归:在函数返回的时候自己调用自己,返回值不能包含表达式
def func(n): return func_dict(n,1) def func_dict(num,product): if num == 1: return product return func_dict(num-1,num*product) print(func(5))
func(5) func_dict(5,1) func_dict(5-1,5*1) func_dict(4-1,4*5*1) func_dict(3-1,3*4*5*1) func_dict(2-1,2*3*4*5*1) 2*3*4*5*1
5.11 全局函数
Python内置函数网站:内置函数 — Python 3.12.4 文档
round() ----- 四舍五入 ,对于奇数来说是标准的四舍五入,但是对于偶数来说小于等于5的都舍去
>>> round(4.5) 4 >>> round(4.6) 5 >>> round(4.4) 4 >>> round(5.4) 5 >>> round(5.5) 6