Python基础知识总结笔记(四)函数
python中的函数
函数中的参数
变量作用域
偏函数PFA
递归函数
高阶函数
BIFs中的高阶函数
匿名函数lambda
闭包Closure
装饰器Decorator
函数式编程Functional Programming
每天都有程序员定时讲解Python技术,分享一些学习的方法和需要留意的小细节,要资料加 624440745
1. python中的函数
■ 函数的意义:
■1.对输入进行变换映射后输出 ,可以进行反复调用。以函数名对代码块进行封装
■2.过程化 VS 结构化
■ 函数的创建及结构:
■定义函数名:def foo1(num):
■参数:num
■函数体
■返回
□有无返回:
有返回值:return返回的是对象,(如返回对象数>1返回元组)。且返回的为最后的一个return值。
无返回值 :无返回值或者return后为空。
print可以有很多,但是return只有一个。
□return与yield的区别:
print:不返回任何的函数
return 结束函数,返回值,当函数被调用时,遇到结尾或return时就准备结束了。只显示最后一个return的值。
yield:丢出一个数,对象变成了生成器–记录当前运行到哪里了。
#函数的意义
n=5
for i in range(n):
print(i)
# 以函数名对以上代码块进行封装
def foo(num): #函数名foo; 参数num
for i in range(num):
print(i)
#然后进行反复调用
# foo()
#对输入进行变换映射后输出
#函数的定义
def foo1(num):#函数名与参数
#函数体
cumsum=0#函数内部的变量
for i in range(num):
cumsum+=i
#返回值
return cumsum
foo1(15)
#函数的返回值-无返回值
def foo2():#函数名与参数
#函数体
cumsum=0
for i in range(15):
cumsum+=i
#无返回值
#或者return后为空
foo2()
#函数的返回值,有返回值
def foo3():#函数名与参数
#函数体
cumsum=0
for i in range(15):
cumsum+=i
#return返回的是对象,(如返回对象数>1返回元组)
return cumsum,cumsum*2
#函数结束
foo3()
#return与print在Notebook上的差异
#print可以有很多,但是return只有一个
# def foo2():
# for i in range(5):
# print(i)
# foo2()
# #函数的参数
# def foo3(num):
# for i in range(num):
# print(i)
# return 'Done'
# foo3(1)
# print(foo3(2))
### 函数的返回
#return与yield关键字
#return 结束函数
def foo1():#不返回任何的函数
print('i\'m foo1,but i return nothing')
def foo2():#使用return返回值
return 'i\'m foo2, this is what i return'
def foo3():#函数被调用时,遇到结尾或return时就准备结束了。
return 'i\'m foo3, this is the first return'
return 'i\'m foo3, this is the secod return'
#yield 丢出一个数--对象变成了生成器--记录当前运行到哪里了
def foo4():
for i in range(5):
return i#执行第一次时foo4函数就结束了
#yield
def foo4():
for i in range(5):
yield i
yield 'f' #再加入一个yield看看会不会被执行
i+=1
g1=foo4()#看一下调用foo4()返回的是什么
type(g1)#看一下g1是个什么样子的对象
next(g1)#继续上一次的位置,进入下一层循环
#执行完最后一次循环,结束 yield语句并抛出StopIteration 异常
2. 函数中的参数
■ 参数:
■语法:
func(positional_args,keyword_args,*tuple_nonkw_args,**dict_kw_args)
positional_args位置参数
keyword_args关键字参数
tuple_nonkw_args非关键字不定长参数
dict_kw_args关键字不定长参数
■ 按参数传递方式:
■位置参数(定位参数,非关键字参数) :位置顺序十分重要,不可缺少个数。对位置敏感,传递时不用指定参数名
■关键字参数:等于号确定。intro=" "
不传关键字参数,函数依旧可以被调用,采用默认值。
传关键字参数,则覆盖默认值。
■位置参数包裹及使用*:一次传入不定长个位置参数。传入n个位置参数。传进来列表[]
■关键字参数包裹及使用 **:一次性传入不定长关键字参数传入n个关键字参数。传进来字典{}
位置参数包裹可以写n个——列表;关键字参数包裹可以写n个——字典
■包裹解包顺序:首先拆位置参数包裹,按顺序给必选,默认,可变。再抓给关键字参数包裹。
■传递不定长参数时,使用包裹:位置参数
■传递参数时,使用包裹:关键字型参数
传递不定长参数时使用包裹——位置参数必须打碎(只传递内容)再传递,传递参数同理。即:列表类型、tuple类型必须(*list);字典类型必须( * *字典)。若传(list)代表的是传对象对不上函数。
l1=[1,5,6,7,2,5,3.5,9,6,3,4]
mysum2(*l1)#mysum2(1,5,6,7,2,5,3.5,9,6,3,4)可以,但是mysum2(l1)不可以,因为相当于是传递了l1为一个list类型的对象。*l1表示可迭代对象,里面有多少对象就当多少对象接受。
1
2
■ 按参数的类型:
■必选(位置参数):必须写、个数要对应
■关键字/默认:*args可变长位置参数,**kwargs可变长关键字参数
其中:
*args列表
**kwargs字典
■ 函数如何处理传入参数
■值传递参数与指针传递参数:
值传递参数:值传递时,变量传递给函数后,函数复制一份,不会影响原有变量。
指针传递参数,会修改参数本身:指针(或引用)传递时,变量传递给函数的是及引用,该引用可以改变原变量
#按参数传递方式
#位置参数
def foo3(companyName,websiteUrl):#位置参数的定义
print('公司名:',companyName,'公司网址:',websiteUrl)
foo3('七月在线','http://www.julyedu.com')
foo3('http://www.julyedu.com',websiteUrl='七月在线')
#位置参数,对位置敏感,传递时不用指定参数名
#关键字参数
def foo4(companyName,websiteUrl,intro='专注AI教育'):#关键字参数的定义intro='专注AI教育'
print('公司名:',companyName,'公司网址:',websiteUrl,'介绍:',intro)
foo4('七月在线','http://www.julyedu.com')#不传关键字参数,函数依旧可以被调用,采用默认值
foo4('七月在线','http://www.julyedu.com',intro='国内领先的AI教育平台')#传关键字参数,覆盖默认值
#如果想一次传入不定长个位置参数,怎么办呢?
#位置参数包裹及使用*
def mysum1(a,b,c):
return a+b+c
mysum1(5,7,15)
#mysum1(5,7) #报错,因为传入的参数少于函数定义时的个数
#mysum1(5,7,15,22) #报错,因为传入的参数多于函数定义时的个数
#这时我们就需要使用包裹*args(tuple类型)进行接收
#位置参数包裹可以写n个——列表;关键字参数包裹可以写n个——字典
def mysum2(*args):
# print(type(args))
return sum(args)
mysum2(5,7,15,22,33)#正常调用
mysum2(5,7)#正常调用
#那同样如果想一次性传入不定长关键字参数,也可以使用一个包裹进行接收
#关键字参数包裹及使用**
def filmInfo(**kwargs):
print(type(kwargs))
for key,values in kwargs.items():
print(key,':',values)
filmInfo(film='羞羞的铁拳',box=3.5)
filmInfo(film='羞羞的铁拳',box=3.5,rate=7.9)
# d1={'羞羞的铁拳':3.5,'box':3.5}
#包裹解包顺序
#首先拆位置参数包裹,按顺序给必选,默认,可变。
#再抓给关键字参数包裹
def scoreReport(name,age,*args,course='python',**kwargs):
#位置;位置;位置参数包裹;关键字(默认,可以不修改);关键字参数包裹
#位置参数包裹可以写n个——列表;关键字参数包裹可以写n个——字典
print('个人信息:',name,age)
for item in args:
print(item)
print('课程信息:',course)
print('每节课成绩:')
for key,value in kwargs.items():
print (key,value)
scoreReport('xiaoming',22,'高中部','三年二班',Lesson1=80,Lesson2=85)
scoreReport('xiaoming',22,'三年二班',course='machine learning',Lesson1=80,Lesson2=85)
# #传递不定长参数时使用包裹-位置参数 必须打碎(只传递内容)再传递,即列表类型必须(*list);字典类型必须(**字典)。若(list)代表的是传对象对不上函数。
l1=[1,5,6,7,2,5,3.5,9,6,3,4]
mysum2(*l1)#=mysum2(1,5,6,7,2,5,3.5,9,6,3,4)
# #zip案例
# l1=[(1,3),(2,4)]
# list(zip(*l1))
# ##传递参数时使用包裹-关键字型参数
# d1={'羞羞的铁拳':3.5,'雷神3':3.1,'战狼2':60}
# filmInfo(**d1)
#值传递,参数本身不会被修改
a=7
b='julyedu'
print('before reference:',a,b)
def foo1(a,b):
a+=1
b+='.com'
print('In foo1 a,b has changed to',a,b)
foo1(a,b)
print('after reference:',a,b)
#结论:值传递时,变量传递给函数后,函数复制一份,不会影响原有变量
print('>'*40)
#指针传递参数,会修改参数本身
l1=[1,2,3.4]
d1={'name':'jack'}
def foo2(a,b):
a.pop()
b['age']=22
print('before reference:',l1,d1)
foo2(l1,d1)
print('after reference:',l1,d1)
#结论:指针(或引用)传递时,变量传递给函数的是及引用,该引用可以改变原变
3. 变量作用域
位置与顺序
■ 标识符的作用域
globals()#全局变量名称空间
locals()#局部变量名称空间
■ 全局变量
■定义:全局变量会一直存在,除非是脚本运行结束或 del 删除它。
■经过函数时:可以被函数内部调用
■ 局部变量
■函数内部创建与访问,当被调用结束时,生命周期结束。
■ 变量的搜索顺序
■覆盖问题:重名,从局部到全局:先从局部找,找不到再去全局找。
■局部作用域->全局作用域:从局部到全局
4. 偏函数PFA
■ 偏函数Partial function application
■使用场景:如果一个函数的参数很多,而在每次调用的时候有一些又经常不需要被指定时,就可以使用偏函数(近似理解为默认值)有些参数无需修改,固定部分参数
只设置了一部分的参数的函数,固定一部分参数,使得被调用时,某些参数被固定住了。
■语法:partical(func,*args,**keywords)
■使用:from functools import partial
■原理:创建一个新函数,固定住原函数的部分参数(可以为位置参数,也可以是关键字参数),偏函数的类型与普通函数不一样,为:functools.partial。
#Partial function application(PFA)
# 只设置了一部分的参数的函数
# 固定一部分参数,使得被调用时,某些参数被固定住了。
#例如我们要定义一个函数将传进来的16进制的字符串,转换为10进制的
def hex2int(num):
return int(str(num),base=16)#base为关键字参数,这个在调用int这个函数时,固定给16。因为这个函数就是用来转换16进制到10进制
hex2int('F')#这时调用,相当于实际上会把10作为*args的一部分自动加到左边,也就是:int('F',base=16),这样就少写了一个函数
#这时也可以使用偏函数,固定int函数的关键字参数base,可以这样定义:
import functools
hex2int2=functools.partial(int,base=16)
#hex2int2('A')
#偏函数能固定位置参数?
#可以
max100=functools.partial(max,100)#定义一个叫max100的偏函数,将这个偏函数的第一个值固定为100
max100(101)#这时调用它,传入的值,都会与100进行比较反并返回。
type(max100)#偏函数的类型与普通函数不一样
5. 递归函数
■ 定义:
■函数在内部调用自身
■ 例子:
■求一个列表中数值的累加
#递归的方法求一个列表中数值的累加
def foo1(num):
if len(num)==1:
return num[0]
else:
# print(num[0],'>'*6)
# print(num[1:],' >'*6)
return num[0]+foo1(num[1:])
foo1([1,2,31,5,6,55])
#使用递归分解质因数
l1=[]
def fenji(num):
num=int(num)
for i in range(2,num):
if num%i==0:
l1.append(i)
nextv=int(num/i)
fenji(nextv)
break#这里的break不加就会硬循环60次
return l1
fenji(60)
#阶乘
def factorial(n):
if n==1:
return 1
else:
return n*factorial(n-1)
factorial (5)
6. 高阶函数
■ 函数的引用与调用
■引用:访问,变量别名(多个别名引用)
一个对象可以被多个变量引用。
■调用:() 最后返回结果
■ 函数对象可以被引用,可以作为参数被传入或作为结果被返回。
■ 高阶函数:
■==一个函数接收另一个函数作为参数。==将函数作为变量。可接受一个指向函数变量的变量名
■ 回调函数:
■函数作为调用函数的结果返回。返回函数
#函数对象的引用 与 调用
num=-5
a=b=c=abs
#引用
print(abs,a)
#调用
a(num)
b(-8.8)
c(7)
#函数名本质即变量,同一个函数对象可以被多个变量引用
def foo():#新建一个函数对象,并用foo这个变量名对其进行引用
pass
del foo#对函数对象的引用可以删除
#高阶函数
def mycalucate(num,func):
return func#返回函数
l1=[5,8,3,6,9,15,22]
mycalucate(l1,max)
mycalucate(l1,min)
mycalucate(l1,sum)
mycalucate(l1,reversed)
#回调函数
def callbackfunc(*num):
return max
callbackfunc(53,5,33)
7. BIFs中的高阶函数
■ filter
■核心点:对每个元素做过滤
语法:filter(function,list可迭代对象)
函数 f 的作用是对每个元素进行判断,返回 True或 False。
filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
■ map
■核心点:对每个元素做映射
语法:map(function, list)
让list的每一个元素依次调用function函数,并获取返回值存入一个新的list中。
■ reduce
■核心点:两两传给func
■Python 3.x中,reduce()函数已经被从全局名字空间里移除了,它和partical一样被放置在 fucntools模块中。使用前需要调用.
语法:from functools import reduce
reduce(function, list)
函数function必须包含两个参数,optional可选,如果存在则表示初值为optional
reduce()对list的每个元素反复调用函数f,并返回最终结果值。
l1=[2,3,5,7,3,4,5,9,'julyedu.com',[2,3,3],5,2]
filter
#语法:filter(function,list)
# 函数 f 的作用是对每个元素进行判断,返回 True或 False
# filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
def myfilter(x):
if x>60:
return True
else:
return False
myfilter(61)
l1=[1,61]
filter(myfilter,l1)
list(filter(lambda x:True if type(x)==str else False,l1))
#map
# 语法:map(function, list)
#让list的每一个元素依次调用function函数,并获取返回值存入一个新的list中。
map(lambda x:(x,l1.count(x)),l1)
# reduce
# 语法:reduce(function, list)
#函数function必须包含两个参数,optional可选,如果存在则表示初值为optional
#reduce()对list的每个元素反复调用函数f,并返回最终结果值。
from functools import reduce
reduce(lambda a,b:a+b,[1,2,3,4,5,6,7,8])
8. 匿名函数lambda
■ 匿名函数lambda: 简化函数
■使用场景:
□返回简单结束 ,不需要专门定义函数
■特点:
□简洁,同一行定义体+声明。不用写return
■定义:
□定义后,赋值给一个变量,做正常函数使用
□lambda关键字定义在高阶函数的参数位上
■语法:
□lambda格式:lambda 接受n个参数:函数体,即: lambda(args1,args2, argsN):expression
#匿名函数--简单的函数功能
#lambda语法:lambda 接受n个参数:函数体
print(type(lambda a,b:a**b ))
#定义
#函数体
#不用写return
#使用1:作为正常函数使用,不推荐
foo=lambda x,y:x+y #不用写return
#lambda
print(foo(5,6))
#使用2:lambda关键字定义在高阶函数的参数位上
d1={'china':15,'India':9,'USA':2,'Japan':1.5} #排序key
sorted(d1.items(),key=lambda x:(x[0],x[1]))#按d1.items()第0个元素升序,国家名
# sorted(d1.items(),key=lambda x:(x[1]))#按d1.items()第1个元素升序,人口数
9. 闭包Closure
■ 闭包的概念
■涉及嵌套函数时才有闭包问题
■内层函数引用了外层函数的变量(参数),然后返回内层函数的情况,称为闭包(Closure)。
■这些外层空间中被引用的变量叫做这个函数的环境变量。
■环境变量和这个非全局函数一起构成了闭包。
■ 闭包的特点:
■函数会记住外层函数的变量
■ 闭包的实现:
10. 装饰器Decorator
■ 定义:
■以函数作参数并返回一个替换函数的可执行函数
■ 简单理解:
■装饰器的作用就是==为已存在的对象添加额外功能 ==
■为一个函数增加一个装饰(用另一个函数装饰)
■本质上就一个返回函数的高阶函数
■ 应用:
■给函数动态增加功能(函数)
■ 定义与使用:
@是python装饰器的简便写法,也叫语法糖。装饰器语法糖在要被包裹的函数前声明。@后面的函数名,是包裹下边函数的函数名extrafoo。
■ 装饰器在Python使用如此方便都要归因于
Python的函数能像普通的对象一样能作为参数传递给其他函数
可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。
#现有如下 三个函数
def foo1():
print ('this is foo1 function')
def foo2():
print ('this is foo2 function')
def foo3():
print ('this is foo3 function')
#现在想为每一个函数都添加一个打印当前时间的功能
#一种解决办法是一个一个修改,在底部添加代码,但问题是,太麻烦了~
import datetime
def foo1():
print ('this is foo1 function')
print(datetime.datetime.now())
def foo2():
print ('this is foo2 function')
print(datetime.datetime.now())
def foo3():
print ('this is foo3 function')
print(datetime.datetime.now())
#另一种办法是,写一个函数,负责打印时间,然后修改那三个函数
import datetime
def printtime():
print(datetime.datetime.now())
def foo1():
print ('this is foo1 function')
printtime()
def foo2():
print ('this is foo2 function')
printtime()
def foo3():
print ('this is foo3 function')
printtime()
#虽然不那么麻烦了,但还是每个函数都要修改,依旧很麻烦。
#法一:我们可以这样解决
def foo1():
print ('this is foo1 function')
def foo2():
print ('this is foo2 function')
def foo3():
print ('this is foo3 function')
def extrafoo(func):
print(datetime.datetime.now())
return func
decorated=extrafoo(foo2)
decorated()
#这样每次调用还是有点麻烦,要先写一个函数接收,再调用。OK,再弄简单一些
#法二:我们可以这样解决: 已有功能foo1,现在想要加计时功能,再写一个函数,利用装饰器。
import datetime
def extrafoo(func):#func代表函数对象
def inner():
print('from inner to execute:',func.__name__)
print('the',func.__name__,'result:',func())#func()代表原始函数
print('extra:',datetime.datetime.now())#加计时功能,在原始函数后面加计时功能。
return inner
@extrafoo#装饰器特性,被装饰的函数定义之后立即运行。@extrafoo可以理解成decorated=extrafoo(foo1)以及decorated()
def foo1():
return 'this is foo1 function--'
#@是python装饰器的简便写法,也叫语法糖
#装饰器语法糖在要被包裹的函数前声明。@后面的函数名,是包裹下边函数的函数名extrafoo
#该语法糖省略了
#decorated=foo(test)
#decorated()
# 装饰器在Python使用如此方便都要归因于
# Python的函数能像普通的对象一样能作为参数传递给其他函数
# 可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。
foo1()
11. 函数式编程Functional Programming
■ 函数式编程思想:
■函数是第一等公民First Class
■函数式编程是一种编程范式,是如何编写程度的方法论。 把运算过程尽量变成一系列函数的调用。属于结构化编程
■ 特点:
■允许函数作为参数,传入另一个函数
■返回一个函数
■ 理解:
■结合本章知识点,案例进行理解
本文的文字及图片来源于网络加上自己的想法,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。