1. 函数简介
- 函数也是一个对象
- 函数用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次调用
语法
def 函数名([形参1,形参2,形参3....]):
代码块
注意:
函数名必须符合标识符的规范(可以包含字母、数字、下划线但是不能以数字开头)
print是函数对象 print()是调用函数
2. 函数的参数
2.1形参和实参
- 形参和实参
形参(形式参数) 定义形参就相当于在函数内部声明了变量,但是并不是赋值 - 实参(实际参数)指定了形参,那么在调用函数时必须传递实参,实参将会赋值给对应的形参,简单来说有几个形参就要有几个实参
2.2 函数的传递方式
- 定义形参时,可以为形参指定默认值。指定了默认值以后,如果用户传递了参数则默认值不会生效。如果用户没有传递,则默认值就会生效
def func(a=1):
return a+1
print(func(func(func())))
#输出结果:4
- 位置参数:位置参数就是将对应位置的实参赋值给对应位置的形参
- 关键字参数 : 关键字参数可以不按照形参定义的顺序去传递,而根据参数名进行传递
- 混合使用位置参数和关键字参数的时候必须将位置参数写到关键字参数前面去
3. 不定长参数
- 定义函数时,可以在形参前面加一个*,这样这个形参可以获取到所有的实参,它会将所有的实参保存到一个元组中
- 带*号的形参只能有一个,可以和其他参数配合使用
- *形参只能接受位置参数,不能接受关键字参数
- 不定长参数不一定非要写在后面,但是要注意,带*号后面的参数,都必须以关键字参数的形式来进行传递
- 形参可以接收其他的关键字参数,它会将这些参数统一保存到字典当中。字典的key就是参数的名字,字典的value就是参数的值
- **形参只有一个,并且必须写在所有参数的后面
def fn2(*a,b,c):#*a只能接收位置参数
print('a=',a)
print('b=',b)
print('c=',c)
fn2(1,2,3,b=4,c=5)
#此处1 2 3为位置参数,4 5为关键字参数(b c为关键字)
'''
a= (1, 2, 3)
b= 4
c= 5
'''
def fn3(**a):
print('a =', a)
fn3(b=1,d = 2,c = 3)
#a = {'b': 1, 'd': 2, 'c': 3}
4. 参数的解包
- 传递实参时,也可以在序列类型的参数前添加星号,这样它会自动的将序列中元素依次作为参数传递
- 要求序列中的元素的个数必须和形参的个数一致
5. 函数的返回值
- 返回值就是函数执行以后返回的结果
- 通过return来指定函数的返回值
- return后面可以跟任意对象,返回值甚至可以是一个函数
- 执行return后,退出函数
- 一个函数没有写return ,或者仅仅写了一个return 那么就相当于 return None
6. 文档字符串
- help()是Python中内置函数,通过help()函数可以查询Python中函数的用法
- 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是对函数的说明
7. 函数的作用域
- 作用域(scope)
- 作用域指的是变量生效的区域
- 在Python中一共有两种作用域
全局作用域:
①全局作用域在程序执行时创建,在程序执行结束时销毁
②所有函数以外的区域都是全局作用域
③在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置进行访问
函数作用域:
①函数作用域在函数调用时创建,在调用结束时销毁
②函数每调用一次就会产生一个新的函数作用域
③在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
注:如果你希望在函数内部修改全局变量的时候,则需要使用global关键字,来声明变量
b = 20
def fn():
global a
a = 10
print('函数内部:a =',a)
print('函数内部:b =',b)
fn()
print('函数内部:a =', a)
''''''
函数内部:a = 10
函数内部:b = 20
函数内部:a = 10
''''''
8. 命名空间
- “命名空间”是Python用于查找给定变量名称并检索与其关联的对象的字典,从名称到对象的映射。
- locals()用来获取当前作用域的命名空间。如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
- 返回值是一个字典
- 命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
- 命名空间查找顺序:局部命名空间 -> 全局命名空间 -> 内置命名空间
#局部命名空间
def fn2():
a = 456
scope = locals()
print(scope)
fn2()
#{'a': 456}
def fn2():
a = 456
scope = locals()
scope['c'] = 123
print(scope)
fn2()
#{'a': 456, 'c': 123}
9. 递归函数
- 递归是解决问题的一种方式,它的整体思想,是将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题
- 递归式函数有2个条件:
①基线条件 问题可以被分解为最小问题,当满足基线条件时,递归就不执行了
②递归条件 可以将问题继续分解的条件
#求n!
def fn(n):
if n==1:#基线条件n
return 1
return n*fn(n-1)#递归条件n
r=fn(10)
print(r)
#3628800
#任意数字做任意幂运算 n ** i 例如 2 ** 3
def fn(n,i):
if i==1:
return 1
return n * fn(n,i-1)
print(fn(5,6))
#3125
10. 高阶函数
接收函数作为参数,或者将函数作为返回值返回的函数就是高阶函数
好处:当我们使用一个函数作为参数,实际是将指定的代码传递给目标函数
lst = [1,2,3,4,5,6,7,8,9,10]
# 定义一个函数 实现偶数
def fn2(i):
if i % 2 == 0:
return True
# 定义一个函数 大于5
def fn3(i):
if i > 5:
return True
# 定义一个函数 3的倍数
def fn4(i):
if i % 3 == 0:
return True
return False
# 定义一个函数,将指定列表中的所有的偶数,保存到一个新的列表
def fn(func,l):
# 参数func:需要传递一个函数对象,其实这个函数对象就是我们想要的一个规则
# 参数l:要进行筛选的列表
# 创建一个新的列表
new_lst = []
# 对列表进行遍历在筛选
for n in l:
# 判断n的奇偶
if func(n):
new_lst.append(n)
# 返回新的列表
return new_lst
print(fn(fn2,lst))
11. 闭包
- 将函数作为返回值返回的函数就是高阶函数,我们也可以称其为闭包
- 闭包的好处
①通过闭包可以创建一些只有当前函数能访问的变量
②可以将一些私有数据藏到闭包中 - 形成闭包的条件
①函数嵌套
②内部函数必须要使用到外部函数的变量
③将内部函数作为返回值返回
注:闭包类似于车,车内可以看到外面,外面看不到车内情况
def foo():
print("hello world in foo")
name = "python"
def bar():#①函数嵌套
print(name)#②内部函数必须要使用到外部函数的变量
print("hello world in bar")
return bar#③将内部函数作为返回值返回
f1=foo()
#hello world in foo
print(f1)
#<function foo.<locals>.bar at 0x037DD268>
def func():
name = "aaaaa"
f1()
#python
#hello world in bar
func()
'''
hello world in foo
<function foo.<locals>.bar at 0x037DD268>
python
hello world in bar
'''
12.装饰器
12.1装饰器的引入
我们可以直接通过修改函数中的代码来完成需求,但是会产生以下一些问题:
①如果修改的函数多,修改起来会比较麻烦
②不方便后期的维护
③这样做会违反开闭原则(ocp)
注:
开闭原则(ocp):程序的设计,要求开发对程序的扩展,要关闭对程序的修改(可以扩展,但不可改源码)
12.2装饰器的使用
- 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
- 在开发中,我们都是通过装饰器来扩展函数的功能的
①求和函数
def sum1():
sum = 1 + 2
print(sum)
sum1()
②写几句代码插进去求上述函数块运行时间
import time
def sum1():
start=time.perf_counter()
sum=1+2
print(sum)
end =time.perf_counter()
print('time used:',end-start)
sum1()
③重新定义一个函数timeit,将sum1的引用传递给他,然后在timeit中调用sum1并进行计时,这样,我们就达到了不改动sum1定义的目的,而且,不论看了多少个函数,我们都不用去修改函数sum1的定义了!
import time
def sum1():
sum = 1 + 2
print(sum)
def timeit(func):
start=time.perf_counter()
func
end =time.perf_counter()
print('time used:',end-start)
timeit(sum1)
④咂一看,没啥问题,可以运行!但是还是修改了一部分代码,把sum1() 改成了timeit(sum1)。这样的话,如果sum1在N处都被调用了,你就不得不去修改这N处的代码。所以,我们就需要杨sum1()具有和timeit(sum1)一样的效果,于是将timeit赋值给sum1。可是timeit是有参数的,所以需要找个方法去统一参数,将timeit(sum1)的返回值(计算运行时间的函数)赋值给sum1。
import time
def sum1():
sum = 1 + 2
print(sum)
def timeit(func):
def test():
start=time.perf_counter()
func
end =time.perf_counter()
print('time used:',end-start)
return test
#这样一个简易的装饰器就做好了,我们只需要在定义sum1以后调用sum1之前,加上sum1= timeit(sum1),就可以达到计时的目的,这也就是装饰器的概念,看起来像是sum1被timeit装饰了!
sum1=timeit(sum1)
sum1()#还是像①中一样只需要调用sum1()就可以得到计算时间
import time
def timeit(func):
def test():
start=time.perf_counter()
func()
end=time.perf_counter()
print("time used:", end - start)
return test
#在定义上加上@timeit这一行与另外写sum1 = timeit(sum1)完全等价
@timeit
def sum1():
sum = 1+ 2
print (sum)
sum1()
13匿名函数:lambda
lambda arg1,arg2,…argn:expression
# 普通python函数
def func(a,b,c):
return a+b+c
print func(1,2,3)
# 返回值为6
# lambda匿名函数
f = lambda a,b,c:a+b+c
print f(1,2,3)
# 返回结果为6
- 无参匿名函数:
t = lambda : True #分号前无任何参数
print(t())
#True
'''
def func():
return True
print (func())
'''
- 带参数匿名函数
lambda x: x**3 #一个参数
lambda x,y,z:x+y+z #多个参数
lambda x,y=3: x*y #允许参数存在默认值
- 匿名函数调用
c = lambda x, y, z: x * y * z
print(c(2,3,4))
#24
- 直接后面传递实参
print((lambda x:x**2)(3))
#9
13.1python中filter/map/reduce函数的使用
13.1.1 filter
①功能:filter主要作用是过滤掉序列中不符合函数条件的元素,当序列中要删、减元素时,可以使用filter函数。返回符合条件的元素组成新列表,通过list打印。
②格式:fliter(function,sequence)
③function可以是匿名函数或者自定义函数,它可以对后面的sequence序列的每个元素判定是否符合条件,返回True或者False,从而留下True的元素;sequence可以是列表、元组或者字符串。
注意:迭代器需要进行列表转换
x=filter(lambda x:x%3==0,[1,2,3,4,5,6])
print(list(x))
#[3, 6]
13.1.2map
①功能:map主要作用是求一个序列或者多个序列进行函数映射之后的值。
②格式:map(function,iterable1,iterable2)
③function中参数值可以是一个,也可以是多个;后面的iterable代表function运算中的参数值,有几个参数值就传入几个iterable。
注意:1.迭代器需要进行列表转换 2.map中如果传入的序列长度不一,会依据最短的序列计算
x=[1,2,3,4]
y=[3,4,6,8,8]
print(list(map(lambda x,y:(x*y)+2,x,y)))
#输出:[5, 10, 20, 34]
13.1.3reduce
①功能:reduce是对一个序列进行压缩运算,得到一个值。
②格式:reduce(function,iterable)
③function中必须传入两个参数(function指明压缩方式),iterable可以是列表或者元组。
注意:reduce使用前需要导包 from functools import reduce,map和filter是内置函数,所以可以直接调用.
from functools import reduce
x=[3,4,6,8,8]
print(reduce(lambda x,y:(x+y),x))#通过求和运算来压缩序列
#输出:29