函数
可以理解为编程方面的函数是一段可重复使用的代码片段
普通函数是有名字的
python中的lambda表达式可以看做是匿名函数
定义并调用一个简单的函数
def A(): # 定义函数的名字,形参列表
print("A") # 函数体
return 'A' # 返回值
A() # 调用函数(没有传实参)
执行顺序
- A()
- def A()
- print(“A”)
将执行的函数赋值给变量,变量就能够拿到函数的返回值
如果打印函数名的话 会显示函数对象的内存地址
<function A at 0x0000015B4D582EA0>
函数的好处
- 代码重用
- 容易维护
- 可扩展性强
函数形参&局部变量
def add(a,b): # a和b就是这个函数的形参
return a+b
形参的作用是接收函数调用时传入的实参的值(默认情况下实参要和形参一一对应)
局部变量是定义在函数内部的变量
只能在函数体内使用,外部无法使用
形参也属于局部变量
函数内部是可以调用函数外部的变量的
如果函数内找不到变量的话 就会在函数外边找
在python中传递参数时,传递的是引用,这个可以通过id来测输出
a = 1
def a_id(a):
return id(a)
if id(a) == a_id(a):
print("是引用,不是复制值")
else:
print("不是引用")
# 运行结果 是引用
globals & nonlocal
如果想要在函数外部使用函数内的变量的话
可以在该变量前面添加globals关键字
虽然可以在函数外部或者其他函数内部进行调用
但是,开发中并不推荐使用全局变量
a = 1
def A():
globals a
a = 2
print(a) #1
A() # 执行A() 相当于把全局变量a的值改成了2
print(a) #2
一般来说 变量命名规范
- 全局/常量 都大写
- 局部变量 标识符命名规则
python中还有一个 nonlocal 关键字
def outer():
def a():
nonlocal a
a = 1
print(a)
def b():
print(a)
def c():
a()
b()
c()
outer()
# 运行结果
# 1
# 1
内层函数中 变量声明为非局部变量
可以理解为介于全局变量和局部变量之间的变量
外层函数的内部都可以随意调用非局部变量
函数外层函数的外部是无法调用非局部变量的
python中形参可以设置默认的值,这个也叫缺省参数
这样即使在调用的时候不给设置默认值的形参传实参也不会报错
def add(a=1,b=2):
return a+b
print(add()) # 3
默认情况下 调用函数时传入的实参要和定义函数时的形参一一对应
形参有默认值的情况下可以不传值
函数参数
python中有三种参数
1. 普通参数
2. 默认参数
3. 可变参数
普通参数就是一个函数中的局部变量,用于接收函数在调用时传入的实参,普通参数要和实参一一对应(普通参数也叫位置参数)
默认参数是普通参数赋默认值(比如a=None,b=None) 有默认参数的情况下,实参可以不传
可变参数 可以传多个实参,也可以不传,详情如下
实参的关键字参数
def println(a, b, c):
print(a, b, c)
println(b=2, a=1, c=20) # 1 2 20
使用关键字参数的点
- 不再需要考虑参数的顺序,函数的使用将更加容易
- 可以只对那些我们希望赋予的参数以赋值,只要其它的参数都具有默认参数值。
还有 普通参数要在关键字参数的左边
可变参数
*形参名 表示实参可以传入任意数量的值[比如 func(1,2,3)]
**形参名 表示实参可以传入任意数量的键值对[比如 func(a=1,b=2)]
def func(*args, **kwargs):
list1 = []
dict1 = {}
for i in args:
list1.append(i)
for k, v in kwargs.items():
dict1[k] = v
print(list1)
print(dict1)
print(type(args))
print(type(kwargs))
func(1, 2, 3, 4, a=1, b=2, c=3)
# 运行结果
[1, 2, 3, 4]
{'a': 1, 'b': 2, 'c': 3}
<class 'tuple'>
<class 'dict'>
如果觉得一个一个写实参的话比较费劲的话,可以这样
# 原来调用函数
def A(a, b, c, *args, **kwargs):
print(a)
print(b)
print(c)
print(args)
print(kwargs)
A(1,2,3,4,5,6,7,z=1,x=2,v=3)
# 现在可以将参数提出来
args = (4, 5, 6, 7)
kwargs = {'z': 1, 'x': 2, 'v': 3}
A(1, 2, 3, *args, **kwargs)
传参的顺序
普通参数,关键字参数,可变参数(*args , **kwargs)
return
return可以返回值
也可以控制函数在什么时候停止(见到return了,后面代码都不执行)
如果没有写return的话 那么函数的返回值为None
def a():
pass
print(a()) # None
如果返回了一个值 就返回该值
如果返回了多个值的话,函数的返回值类型为tuple
break是用来结束循环的,return是结束函数的
函数的嵌套
函数体中可以调用其他函数
def a():
print(0)
def a1():
a()
print(123)
def b1():
a1()
print(456)
b1()
执行顺序
def a(): # 6
print(0) # 7
def a1(): # 4
a() # 5
print(123) # 8
def b1(): # 2
a1() # 3
print(456) # 9
b1() # 1
# 10 结束
回调
def a(func):
func()
def b()
print("b")
a(b)
递归
就是一个函数在内部调用自身
递归必须要有一个明确的结束条件 否则就进去了一个死循环
lambda表达式
在python中lambda表达式可以看成是匿名函数
举例
def A(func):
return func
def add1(x):
return x+1
f = A(add1) # 经add1函数的引用传到A()中 经过赋值之后f和add1指向同一个函数
a =f(2)
print(a)
---------------------------
def A(func):
return func
print(A(lambda x:x+1)(2)) # 打印3
一个普通的函数结构
def 函数名(形参列表):
函数体
返回值
而lambda表达式
lambda 形参列表:返回值表达式/语句
# 如果形参列表为空的时候 可以写成 lambda : 返回值表达式/语句
a = lambda : print(123)
a()
调用有名字的函数 直接 函数名(参数列表)
如果有返回值的话用外部变量接收
调用一个lambda表达式的话
变量 = lambda表达式 然后变量()
这样的话实际上就是给了匿名函数一个函数名
高阶函数
函数式编程: 把函数当做参数传给另一个函数 以及 返回值中包含函数
map
map类的__init__
方法
def __init__(self, func, *iterables)
第2个参数是函数名/匿名函数
第3个参数是可以传一个或多个可迭代对象
# map函数
li = map(lambda x:x+1,[1,2,3,4,5])
print(li) # <map object at 0x0000019D4715B240>
print(type(li)) # <class 'map'>
print(list(li)) # [2, 3, 4, 5, 6]
简单模拟一下map函数
def add_one(x):
return x + 1
def mapTest(func, iterable):
li = []
for i in iterable:
res = func(i)
li.append(res)
return li
li = mapTest(add_one, [1, 2, 3, 4, 5])
print(li)
还有 func后面跟多少可迭代对象 func的形参就有几个
li = map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6])
print(list(li)) # [5, 7, 9]
# 首先 li1[0]作为x li2[0]作为y 传到lambda表达式
# ...
func如果逻辑复杂的话 就在外部定义函数
如果不算复杂的话可以用lambda表达式来解决
比如将[1,2,3] 变成[‘1’,’2’,’3’]
li = list(map(lambda x:str(x),[1,2,3]))
print(li)
# 当然 用列表推导式也能实现
li2 = [str(i) for i in [4,5,6]]
print(li2)
reduce
py2中可以直接用reduce函数
而py3中需要 from functools import reduce
def reduce(function, sequence, initial=None)
from functools import reduce
num = reduce(lambda x, y: x * y, [1, 2, 3, 4])
print(num) # 24
# 首先 li[0] 作为x li[1]作为y
# 上一次的返回值 作为x li[2]作为y
# ...
算阶乘的话可以用reduce
num = reduce(lambda x, y: x * y, range(1, 11))
print(num) # 3628800
5050也可以
num = reduce(lambda x, y : x + y , range(1, 101))
print(num)
reduce的第三个参数 是初始值
比如上面的5050
如果初始值传个101的话 返回值就是 5050+101 = 5151
列表转换成字符串也可以用reduce
from functools import reduce
a = [1,2,3]
s = reduce(lambda x,y:str(x)+str(y),a)
print(s) # 123
print(type(s)) # <class 'str'>
filter
filter的作用是过滤
def __init__(self, function_or_None, iterable)
传入的func可以是None 也可以是一个返回值为布尔值的函数
可迭代对象中的元素传入func,如果函数的返回值为False
那么这个不符合条件的元素会被过滤掉
li = filter(lambda x: True if x < 5 else False, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(list(li))
总结
map(func,*iterable)
将可迭代对象中的每个元素传入到func中 批量进行处理
会得到一个返回值”列表” 是一个map类型对象
map类型的对象可以迭代 也可以转换成list
filter(func,*iterable.init)
func是一个返回值类型为布尔值的函数/lambda表达式
将可迭代对象中的每个元素传入到func中
如果返回值为True的话,元素会被添加到返回值”列表”中 是一个filter类型对象
如果返回值为False的话,元素会被过滤掉
reduce可以理解为把序列进行合并操作
比如序列是[1,2,3]
func是 lambda x,y:x+y 那就等价于 将序列遍历然后进行累加 并返回
func是 lambda x,y:x*y 那就等价于 将序列遍历然后进行累乘 并返回
func是lambda x,y:str(x)+str(y)
那就等监狱 将序列中的所有元素转换成字符串 然后进行拼接
如果有初始值(init)的话,就从初始值开始