1.1函数
1.1.1什么是函数
函数就是程序实现模块化的基本单元,一般实现某一功能的集合。
函数名:就相当于是程序代码集合的名称
参数:就是函数运算时需要参与运算的值被称作为参数
函数体:程序的某个功能,进行一系列的逻辑运算
return 返回值:函数的返回值能表示函数的运行结果或运行状态。
1.1.2函数的作用
- 函数是组织好的,可重复使用的,用来实现单一,或者相关功能的代码。
- 函数能够提高应用的模块性,和代码的重复利用率
我们已近知道python提供了许多内置函数,比如print(),我们自已创建的函数称为内置函数
1.1.3定义函数的语法
def 函数名(参数): 函数体 return 返回值内容
1.1.4函数定义规则
- 函数代码以def关键词开头,后接定义函数的名称和圆括号,冒号():
- 函数内容以冒号":"开始,并且缩进
- 函数内容的第一行内容可选择性使用文档字符串---用来定义该函数的说明
- 函数的返回值: return [返回值内容] 用于结束函数,返回一个值,表示程序执行的结果。
- 函数不带return 默认返回None 返回值可以是任何类型的数据(数字,字符串,函数,列表,元祖,字典等),也可以是一个表达式
- 函数参数:任何传入参数和自变量必须放在圆括号中间,圆括号之间用于定义参数。
1.1.5函数调用
定义函数语法
def printinfo(): print("hello world") return
调用函数
printinfo() #函数执行结果 hello world
查看函数返回值
print(printinfo()) #结果 hello world None #默认函数值返回类容
其他返回值示例
def printinfo(): print("hello world") return [111+222] print(printinfo()) #结果 hello world [333] #返回值内容
1.1.5函数参数
注:形参和实参(定义函数时,圆括号(参数)中的所有参数都是形式参数也称为形参,调用函数中,圆括号(参数)中的参数称为实际参数,也叫实参)
1)必须参数::
2)关键字参数:
3)默认参数:
4)可变参数(*args,**kwargs):
1.必须参数:
从字面理解:必须要传入参数
传入的参数:与定义的形参顺序一一对应
def stuinfo(name,age): print(name,age) return #在不传入参数 stuinfo() #调用函数 #函数执行结果 TypeError: stuinfo() missing 2 required positional arguments: ‘name‘ and ‘age‘ #报错,提示类型错误,该函数,缺少两个位置参数
def stuinfo(name,age): print(name,age) return stuinfo("zhangsan",18) #函数执行结果 zhangsan 18
2.关键字参数
def stuinfo(name,age,hobby): print(name,age,hobby) return #参数位置匹配,关键字参数,与形参的位置顺序无关, stuinfo(age=19,name="lisi",hobby="run") #name= age= hobby=就是关键字参数 #函数执行结果 lisi 19 run
3.默认参数
默认参数必须指向不变的对象
当函数有多个参数,把变化大的参数反正前面,变化小的参数放在后面。变化小的参数就作为默认参数。
默认参数好处:降低调用函数的难度
#默认参数,可以直接使用用,也可以修改默认参数值 def grade(name,age,city="BeiJing"): #city="BeiJing" 就是默认参数 print(name,age,city) # grade("yangjian",age=18) grade("lala",age=18,city="shanghai") #grade函数执行结果 lala 18 shanghai
4.可变参数
*args **args
用途:在定义函数需要,每个定义函数功能的都可以继续优化,所以我们需要用动态参数
如果把参数写死了,后期继续修改完善的功能的,修改该函数功能则会相当麻烦
*args 结果类型是元祖,传递值是任意类型
def test(*args): print(args) test(123456,[12,45,88],{"name":"qw","age":15}) #可以传递任意参数的类型 #函数执行结果 (123456, [12, 45, 88], {‘name‘: ‘qw‘, ‘age‘: 15})
**kwargs结果类型是字典,传递值是以key=value方式传入
def test1(**kwargs): print(kwargs) test1(name="xiha",age="12") #执行结果 {‘age‘: ‘12‘, ‘name‘: ‘xiha‘}
函数* 和 ** 解包
#* def test(*args): print(args) test(*[1,2,3,4,5,6,7,8,9]) #*参数解包,把【元素】 循环出来,添加到元祖中 #结果 (1, 2, 3, 4, 5, 6, 7, 8, 9)
def test1(**kwargs): print(kwargs) test1(**{"hobby":456,"number":789}) #**参数解包,把key:value 循环出来,添加到字典中 #结果 {‘number‘: 789, ‘hobby‘: 456}
函数参数组合
def f2(a, b, c=0,*args,**kwargs): print(‘a =‘, a, ‘b =‘, b, ‘c =‘, c, args,kwargs) f2(12,b=12,c=89,aa="as",bb="xxx") #结果 a = 12 b = 12 c = 89 () {‘bb‘: ‘xxx‘, ‘aa‘: ‘as‘}
函数参数总结:
1.形参的位置顺序,必须与实参的顺序一一对应,缺一不行,多一不行
2.关键字参数,无须一一对应,缺一不行,多一不行
3.位置参数必须在关键字参数左边
4.默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误
1.2全局变量和局部变量
在子程序中定义的变量称为局部变量,只在子程序内部生效,
在程序一开始定义的变量称为全局变量
全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
当全局变量与局部变量同名时:在定义局部变量的子程序内,局部变量起作用,在其他地方全局变量起作用
name = "xixi" #全局变量 def change_name(): name = "haha" #局部变量只在函数局部作用域内生效 print("我的名字",name) return change_name() print(name) def me(): global name #声明name是全局变量 global name = "yj" #修改name全局变量的值 print(name) return me()
如果全局变量是可变的数据类型,函数可以对全局变量内部直接进行修改
eng = ["merry","jack","petter"] def chang(): eng.append("mali") print(eng) return chang()
总结:
一般写程序变量的命名规则
###全局变量变量名大写
###局部变量变量名小写
- 函数优先读取局部变量,能读全局变量,无法对全局变量重新赋值操作,#全局变量是不可变的类型
- 全局变量是可变类型,函数可以对全局变量进行操作
- 函数中有global关键字,变量本质就是全局变量,可读取全局变量,也可操作全局变量
1.3函数之间嵌套
name = "YangJIan" #最外层 def change_name(): #第二层 name = "YangJIan2" def change_name2(): #第三层 name = "YangJIan3" print("第3层打印", name) change_name2() # 调用内层函数 print("第2层打印", name) change_name() #先执行局部函数的打印, print("最外层打印", name) # 第3层打印 YangJIan3 # 第2层打印 YangJIan2 # 最外层打印 YangJIan
注:多层函数嵌套,子级函数,只在子级函数内部生效。父级函数能调用子级函数的功能
1.4递归函数
1.在函数内部,可以调用其他函数,如果一个函数在内部调用自身本身,这个函数就是递归函数。
2.在使用递归策越是,必须有一个明确的敌对结束条件,称为递归出口
函数调用的时候,每次调用时要做地址保存,参数传递等。
如果函数包含了对其自身函数的调用,该函数就是递归。如下
def foo(n): #实现阶乘 if n == 1: return n # 当满种条件n==1才执行return 操作 res = n*foo(n-1) #调用自已本身的函数的结果(再判断条件是否满足条件)给res , return res print(foo(5)) #120
递归算法所所体现的重复一般有的要求:
1.每次调用在上次规模上都有有所减小:
2.每次递归调用都是有明确条件的。
3.相领两次的重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出(返回值结果))就作为后一次的输入;
4.在问题的规模得到满足条件时,而不再进行递归调用。
1.5函数式编程
面向过程编程:我们通过把大段代码拆成函数,通过一层一层的函数,可以把复杂的任务分解成简单的任务,这种一步一步的分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
函数式编程:是使用一系列函数去解决问题,函数式编程就是根据编程的范式来的出想要的结果,只要是输入时确定的,输出就是确定的。
1.6高阶函数
能把函数作为参数传入,这样的函数就称为高阶函数。
1.6.1函数即变量
以python的内置函数print()为列,调用该函数一下代码
>>> print("hello world") hello world #只写print >>> printin function print> #可见print("hello world")是函数调用,而print是函数本身
要获得函数调用执行的结果,我们把结果赋值给变量:
>>> aa = abs(-20) >>> aa 20
如果把函数本身赋值给变量
>>> p = print >>> pin function print> #函数本身可以赋值给变量,变量可以指向函数
我们通过变量来调用这个print函数,验证结果如下
>>> p("check") check
总结:函数名也是变量,对于print()这个内置函数,完全可以把函数名print看成变量,它指向一个可以打印任何东西的函数
注:实际程序代码绝不能这么写,上面只是为了举例说明,要恢复print函数,请重启python的交互环境
1.6.2传入函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一函数作为函数,这种函数就称为高阶函数,
函数的返回值是一个函数名,也是高阶函数。
例如:一个简单的高阶函数
def add(x,y,z): return abs(x)+abs(y) aa = add(12,23,abs) #函数执行的结果 赋值给 aa print(aa) #查看aa的值 #35 #注,abs()函数是求一个整数的绝对值
1.7匿名函数
什么是匿名函数:
在python中有一个匿名函数lambda,匿名函数就是指:无需定义标识符(函数名)的函数或子程序。
定义lambda表达式:
lambda arguments:express #arguments 参数(可以有多个参数) #express 表达式 #lambda返回值是一个函数的地址,也就是函数对象 aa = lambda arguments:express #把的到lambda函数地址,赋值给变量aa 查看这个lambda函数地址 ,用aa(argument) 查看这个函数的值
例1
def pf(x=0): return x**2 print(pf(3))
aa = lambda x:x**2 print(aa(4)) #16
总结:
1.lambda函数可以参数可以有多个,包含的表达式不能超过一个,不要试图向lambda函数中塞入太多东西,如果你需要做复杂的功能,应该定义一个普通函数,想定义什么就定义什么。
2.lambda函数用在需要封装特殊的,非重用代码上,避免令我们的代码充斥大量的单行函数。
map函数
map()函数,map映射
map(func,iterable)
map()函数接受两个参数,一个是函数,一个可迭代的对象(iterable),map将传入的函数依次作用到序列的每个元素,并把结果作为新的 可迭代的对象 的结果返回
例:有个函数,f(x) = x+1 把得到的数字 加1 要把这个函数作用在一个[1,2,3,4,5,6]上
number = [1,2,3,4,5,6] #1.用普通函数定义方法 def add_one(x): return x+1 def map_test(func,arrey): res = [] for i in arrey: i = func(i) res.append(i) return res print(map_test(add_one,number)) #[2, 3, 4, 5, 6, 7] #2.用lambda函数定义的得到结果,借助1定义的map_test函数 print(map_test(lambda x:x+1,number)) #[2, 3, 4, 5, 6, 7] #3.用map()本身函数去定义 print(list(map(lambda x:x+1 ,number))) #[2, 3, 4, 5, 6, 7] #注:map()得出的结果是一个iterator ,需要用list()函数让它个整个序列都计算出来返回一个list
我们可能会想,写一个循环,也可以计算出结果,但要实现多个功能,是不是也要写多个循环 例:得出每个列表中元素的平方或则n次方
map()作为高阶函数,事实上把运算规则抽象了,不但可以计算简单的 f(x) = x+1 ,也能计算更复杂的函数。
总结:map() 处理序列中的每个元素,得到的结果是一个 iterator ,需通过list(iteratro),该list元素个数,与原来位置一样
reduce函数
在python2可以直接用reduce()函数
在python3需要调用reduce模块
from functools import reduce reduce(function, sequence, initial=None) #该函数的默认用法
reduce函数,将function作用sequence序列的元素,每次携带一对(先前的结果以及下一序列的元素),连续的将现有的结果和下一个作用在获得的随后的结果上,最后得到我们的序列为一个最终结果的返回值
number1 = [2,3,4,10] #1.普通函数定义 def chengfa(x,y): return x*y #返回得到两个数相乘的结果 def reduce_test(func,seq,init=None): if init is None: res = seq.pop(0) #seq删除第一个元素,并获取删除这个元素 赋值给res else: res = init for i in seq: res = func(res,i) #循环一次,执行func这个函数 return res print(reduce_test(chengfa,number1)) #240 print(reduce_test(chengfa,number1,10)) #2400 #如果给了init 初始值,就是从初始值 乘以列表的每个元素的的出结果 #2.lambda函数,借助reduce_test()函数定义 print(reduce_test(lambda x,y:x*y,number1,init=3)) #720 #3.使用reduce(),结合lambda() print(reduce(lambda x,y:x*y, number1)) #240 得到列表所有元素,相乘的结果 number1 = [2,3,4,10] #1.普通函数定义 def chengfa(x,y): return x*y #返回得到两个数相乘的结果 def reduce_test(func,seq,init=None): if init is None: res = seq.pop(0) #seq删除第一个元素,并获取删除这个元素 赋值给res else: res = init for i in seq: res = func(res,i) #循环一次,执行func这个函数 return res print(reduce_test(chengfa,number1)) #240 print(reduce_test(chengfa,number1,10)) #2400 #如果给了init 初始值,就是从初始值 乘以列表的每个元素的的出结果 #2.lambda函数,借助reduce_test()函数定义 print(reduce_test(lambda x,y:x*y,number1,init=3)) #720 #3.使用reduce(),结合lambda() from functools import reduce print(reduce(lambda x,y:x*y, number1)) #240
print(reduce(lambda x,y:x+y,range(1,101)))
filter函数
filter()函数用于过滤序列
和map()类似,filter()也接受一个函数和一个序列(可迭代的对象,也就是能被for循环),和map()不同的是,fillter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
例:
aa = [‘A‘, ‘‘, ‘B‘, None, ‘C‘, ‘ ‘] #1.自定义函数测试 def not_empty(s): return s and s.strip() def filter_test(func,iter): res = [] for i in iter: i = func(i) if i: res.append(i) return res print(filter_test(not_empty,aa)) #[‘A‘, ‘B‘, ‘C‘] #2.filter内置函数测试 print(list(filter(not_empty,aa))) #[‘A‘, ‘B‘, ‘C‘]
filter()这个函数,关键在于正确实现一个筛选函数,
注:filter()函数返回的是一个iterator,内存地址,需要看内存地址的值, 用list()函数或得该地址的值
sorted函数
sorted()函数也是一个高阶函数,它可以接收key
sorted排序,排序是比较元素的大小,如果是数字可以直接比较,如果是字符串或则两个dict(字典)?
sorted()传入的参数是可迭代的对象,返回值的对象是一个列表
例:
aa = [11,-10,20,21,30,-40] print(sorted(aa))
接收一个key函数来实现自定义排序
例:根据绝对值大小来进行排序
aa = [11,-10,20,21,30,-40] print(sorted(aa,key=abs)) #[-10, 11, 20, 21, 30, -40]
例:字符串排序
print(sorted("hello")) #[‘e‘, ‘h‘, ‘l‘, ‘l‘, ‘o‘] print(sorted(["hello","ho","haha"])) # [‘haha‘, ‘hello‘, ‘ho‘]
注:默认情况下,对字符串排序是按照ASCII编码表的大小进行比较的
最后总结:
python内置的几个高阶函数:map() ,reduce(),filter,sorted()