函数
定义函数
def testAbs(num):
return abs(num)
print(testAbs(-1))
返回多个值
这其实是一个假象,返回的是一个tuple,而tuple可以省略括号,而多个变量可以同时接收一个tuple
def mulValueReturn():
a = 12
b = 13
return a, b
a, b = mulValueReturn()
print(a)
print(b)
声明参数类型
def test(data: str):
pass
声明返回值类型
from typing import Optional
# 返回值为字符串
def test1(data) -> str:
return 'String'
# 返回值是int或者Node
def test1(data: int) -> Optional[int]:
return None if data == 0 else data
默认参数
Python中可以使用 key=xxx 来跳过前面的默认参数
def children(name, gender, age=6, city='Shang Hai'):
print(name)
print(gender)
print(age)
print(city)
children('kk', '女', 7)
# 可以跳过第3个默认参数
children('ff', '男', city='Guang Zhou')
Python中的默认参数最好传不可变类型,否则多次调用,默认参数会发生变化
def testDefaultParams(end=[]):
end.append('end')
print(end)
testDefaultParams()
testDefaultParams()
可变参数
*args
其实就是把传入的n个参数打包成一个元祖
def mySum(*num):
res = 0
for x in num:
res = res + x
return res
print(mySum(1, 2, 3, 4, 5, 6))
test = [1, 2, 3]
print(mySum(test[0], test[1], test[2]))
# 如果本身就是一个列表或元祖,可以通过 *variable 的方式调用
print(mySum(*test))
关键字参数
**args
必须以key=value的方式调用,函数内部会自动转换成字典
def person(name, age, **other):
print('name', name, 'age', age, 'other', other)
person('kk', 7)
person('ff', 20, city='Shang Hai', gender='男')
testMap = {'hobby': 'coding', 'height': 188}
# 如果本身就是一个字典,可以通过 **variable 的方式调用
person('Zhang San', 18, **testMap)
命名关键字参数
使用 *
作为占位符,*
后面的参数必须以key=value的方式调用
跟关键字参数不同的是,函数内部不会自动转换成字段
def person(name, age, *, city, phone):
print('name', name, 'age', age, 'city', city, 'phone', phone)
person('BestLove', 30, city='上海', phone='110')
如果参数中已经有一个可变参数,则不再需要单独使用 *
作为占位符了
def person(name, age, *args, city, phone):
print('name', name, 'age', age, args, 'city', city, 'phone', phone)
person('BestLove', 30, city='上海', phone='110')
person('BestLove', 30, '可变', '加长', city='上海', phone='110')
参数组合
Python中可以用 必选参数、默认参数、可变参数、关键字参数和命名关键字参数 进行组合使用
但参数的顺序必须为:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
不建议使用太多的组合,这样会使得代码的可读性变差
args -> args='xxx' -> *args -> **args -> *,args1,args2... 或 *args,args1,args2...(可变后面可以直接接命名关键字参数)
递归函数
def testRecursion(num):
if num == 1:
return 1
return num * testRecursion(num - 1)
print(testRecursion(4))
高阶函数
def add(a, b, func):
return func(a) + func(b)
print(add(2, -5, abs))
map 迭代器对象的每一个元素依次运行指定函数,最终返回一个迭代器对象
def myPow(num):
return num * num
res = map(myPow, [1, 2, 3, 4, 5, 6])
print(list(res))
reduce 迭代器对象的每一个元素依次运行指定函数,每次运行的结果会作为下一次运行的第一个参数传入
from functools import reduce
# x为上次运行的结果,y为本次传入的参数
def add(x, y):
print(x, '---', y)
return x + y
# 如果没有初始值,第一次会传入2个参数,即:x=1,y=2
print(reduce(add, [1, 2, 3, 4]))
# 如果存在初始值,第一次会传入初始值和一个参数,即:x=0,y=1
print(reduce(add, [1, 2, 3, 4], 0))
常用的高阶函数还有很多,如:filter sorted 等
返回函数
不返回函数处理结果,只返回函数处理的过程
def lazySum(*args):
def sum():
res = 0
for x in args:
res += x
return res
return sum
func = lazySum(1, 2, 3, 4, 5)
print(func())
匿名函数
当一个函数返回了一个函数后,其内部的局部变量还被新函数引用
def count():
fs = []
for i in range(1, 4):
def f():
return i * i
fs.append(f)
return fs
for f in count():
print(f()) # 输出9 9 9,因为当 f 调用的时候,i已经变成3了
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变
def count():
def f(i):
def g():
return i * i
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs
for i in count():
print(i())
lambda
# lambda 和 func 等效
f = lambda x: x * x
def func(x):
return x * x
print(f(2))
print(func(2))
装饰器
import functools
# 两层嵌套
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2020-12-12')
now()
print(now.__name__)
# 三层嵌套
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print('2020-12-12')
now()
# 如果不加 @functools.wraps(func) now.__name__ 会变成 wrapper
print(now.__name__)
偏函数
通过 functools.partial 创建 8进制 int 强转的偏函数
偏函数与柯里化
- 偏函数可以接受不只一个参数,它被固定了部分参数作为预设,并可以接受剩余的参数
- 柯里化是将函数转化为多个嵌套的一元函数,也就是每个函数只接受一个参数
import functools
i = int('12345')
print(i)
i = int('12345', base=8)
print(i)
int8 = functools.partial(int, base=8)
i = int8('12345')
print(i)