函数式Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计 => 函数就是面向过程的程序设计的基本单元
函数式编程就是一种抽象程度很高的编程范式(范式就是标准的意思),存粹的函数式编程语言编写的函数没有变量 => 任意一个函数,只要输入是确定的,输出就是确定的,这种存函数我们称之为没有副作用. 而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输
入,可能得到不同的输出,因此,这种函数是有副作用的.
函数式编程的一个特点就是 => 允许把函数本身作为参数传入另一个函数,还允许返回一个函数. (函数作为参数,函数作为返回值)
高阶函数
两个概念
变量可以指向函数 2. 函数名也是变量
变量可以指向函数
# 以python内置的abs()为例子
>>> print(abs(-10))
10
# 如果是只书写abs这个函数变量名,那么是指向的一个函数
>>> abs
# 可见 变量名() 这就是函数调用的方式
>>> x = abs
>>> x(-10)
10
>>> x
函数名也是变量
# 如果把 abs 指向一个int,那么abs这个变量就指向函数了
>>> abs = 10
>>> abs(-10)
Traceback (most recent call last):
File "", line 1, in
TypeError: 'int' object is not callable
>>>
高阶函数示例
(函数式编程的特点就是 => 允许函数作为参数,允许函数为返回值)
把函数作为参数传入,这样的函数就是高阶函数,函数式编程就是指这种高度抽象的编程范式.(高阶函数是函数式编程的一个例子)
Python内建的高阶函数有map、reduce、filter、sorted.
"""
既然变量可以指向函数,函数的参数能接收变量,
那么一个函数就可以接收另外一个函数作为参数,这种函数就成为高阶函数.
"""
def add(x,y,f): # f 传递过来的是指向函数的一个变量
return f(x) + f(y) # abs(-10) + abs(-5)
print(add(-10,-5,abs))
内建高阶函数map的使用
需求: 给定一个序列,需要把该序列的每一项都平方后,返回一个新的序列
"""
接收两个参数,一个 函数名, 一个 可变的可迭代对象(注意理解 *,也就是可以传入一个或者传入多个序列)
map(func, *iterables) --> map object
Make an iterator that computes the function using arguments from
each of the iterables. Stops when the shortest iterable is exhausted.
"""
# 1. 将所有一个序列全部平方,放回新的字符串
a = [1,2,3,4,5,6]
# 传统列表生成式 (或者直接写循环)
b = [x**2 for x in a]
print(b)
# 使用map高阶函数
c = map(lambda x:x**2,a) # 注意,返回的是一个map对象(可迭代的对象),要将其list
# 判断一下map()的返回值是不是一个可迭代对象
# 导入这个迭代器,可迭代对象都是其子类
from collections.abc import Iterator
print("map()返回值是否为可迭代对对象: %s" % isinstance(c,Iterator))
# 可迭代对象的话可以直接list() 转变为一个列表
print(list(c))
# 2. map实现将list所有数字转为字符串
# 注意,map是逐项操作,不是列表的拼接,列表拼接的话直接 listA + ListB 即可
b = [str(x) for x in a] # 列表生成式
print(b)
c = map(lambda x:str(x),a)
print(list(c))
# map函数实现传入两个列表,每个数字相加
a = [1,2,3,4]
b = [9,8,7,6]
c = map(lambda x,y:x+y,a,b) # 注意:这里传入了两个序列
print(list(c))
内建高阶函数reduce的使用
reduce主要用于序列的求和
reduce就是把一个函数作用在一个序列[x1,x2,x3...]上,这个函数必须接收两个参数(注意了,是两个参数),reduce把结果继续和序列的下一个元素做累加计算(遍历完这个序列就结束),其效果就是 =>
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
# reduce函数是需要导入的
from functools import reduce
""" 查看官方文档的说明 => (其实说明一般都会给例子)
reduce(function, sequence[, initial]) -> value
Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.
"""
# 1. 计算一个序列的求和
a = range(1, 11)
res = reduce(lambda x, y: x + y, a)
print("reduce计算累加和: %s " % res)
# 2. 将序列每个元素乘2加上另外一个元素 => 实际上就是计算2进制的方法
a = [1, 1, 1, 1] # 估计结果为15
res = reduce(lambda x, y: x * 2 + y, a)
print(res)
内建高阶函数filter的使用
主要用于函数的过滤
Python 内建的filter()函数用于过滤序列。
和map()类似,filter()也接收一个函数和一个序列。
和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False 决定保留还是丢弃该元素。
"""
filter(function or None, iterable) --> filter object
Return an iterator yielding those items of iterable for which function(item)
is true. If function is None, return the items that are true.
"""
# filter 用法与 map 类似,都是依次作用于每一项
# 根据每一项的 true or false 决定是否保留该项
# 1. 保留序列的奇数,过滤偶数
a = range(1, 11)
b = filter(lambda x: x % 2 != 0, a)
print(list(b)) # 得到过滤的序列
# 2. 把一个字符序列的空字符删除
# 补充知识: None,和 ""(空串) 都是会被判断为false
# " "(3个空格) 是true,所以可以去除首尾空格
a = ['A', '', 'B', None, 'C', ' ']
b = filter(lambda x: x and x.strip(), a)
print(list(b))
内建高阶函数sorted的使用
用于对序列的排序,可以自己规定比较规则
高阶函数 sorted,使用 key=f 实现自定义排序,和Java的Comparator进行比较
"""
sorted(iterable, *, key=None, reverse=False) => 还是查看一下文档靠谱
def sorted(*args, **kwargs): # real signature unknown 真实签名未知
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customize the sort order, and the
reverse flag can be set to request the result in descending order.
"""
# 1. sorted对list进行排序 (默认升序)
a = [1, 33, 6, -20, 34]
b = sorted(a) # 返回的是一个新的序列
print("sorted是否在原来序列进行排序: %s" % (id(a) == id(b)))
print(b)
b = sorted(a, reverse=True) # 查看文档才知道 **kwargs 具体是什么
print(b)
# 2. 对字符串进行排序 => 默认按照ASCII码大小排序
# A:65 a:97
# 第一个字符决定不了顺序就看第二个字符,依次下去
a = ["abc", 'ad', "ABC", "D", "d", 'C']
b = sorted(a)
print(b)
b = sorted(a, reverse=True) # 字符串逆序
print(b)
# 3. sorted是一个高阶函数,key=函数,实现自定义排序
# 3.1 对数值列表,按照绝对值大小进行排序
a = [1, 33, 6, -20, 34]
# key = f => 应该是先作用在每一项,然后再去进行比较的
b = sorted(a, key=abs) # 按照绝对值大小进行排序
print(b)
# 3.2 对字符串列表,忽略大小写进行排序
a = ["abc", 'ad', "ABC", "D", "d", 'C']
# 都先把每项统一为大写字母或小写字母
# b = sorted(a, key=str.lower)
b = sorted(a, key=str.upper)
print(b)
匿名函数
Python中使用lambda来声明一个匿名函数
lambda arg1,arg2.... : <表达式>
1. lambda表达式的语法: lambda arg1,arg2,arg3... : <表达式>
其中arg1/arg2/arg3 为函数的参数。<表达式>相当于函数体。运算结果是:表达式的运
算结果。
2. 匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结
果。 => **注意:只能有一个表达式,如果是多个表达式的话就写回正常定义的函数**
# 在python中使用lambda来声明一个匿名函数
# 1. 匿名函数其实也可以使用一个对象来指向 (函数也是一个对象)
f = lambda a, b, c: a + b + c
print(f(1, 2, 3))
# 2. sorted对自定义对象进行排序
# 自定义对象排序的话一定要指定依据什么属性进行比较
# 初始化一个学生类
class Student:
def __init__(self, age, name):
self.name = name
self.age = age
stu1 = Student(11, 'zhangsan')
stu2 = Student(21, 'lisi')
stu3 = Student(31, 'wangwu')
student_list = [stu1, stu2, stu3]
# 按照年龄降序排序
a = sorted(student_list, key=lambda x: x.age, reverse=True)
for x in a:
print("name: %s, age: %d" % (x.name, x.age))
print("=========")
# 按照姓名升序排序
a = sorted(student_list, key=lambda x: x.name)
for x in a:
print("name: %s, age: %d" % (x.name, x.age))
闭包
闭包就是一个函数
闭包是为了后面学习装饰器做铺垫
1. 什么是闭包
闭包其实就是一个函数.
2. 如何创建闭包 (需要满足3个条件)
1) 要有函数的嵌套(外部函数,内部函数)
2)
3. 如何使用闭包
# 1. 使用闭包,完成两个数的和
# 传统函数
def sum(a, b):
return a + b
# 使用闭包
def fOut(a): # 外层函数
def fIn(b): # 内层函数
# 如果内部函数要修改外部函数的变量 => nonlocal
# nonlocal a
# a += 100
return a + b # 内层函数要使用外层函数的变量
return fIn # 外层函数返回内层函数名
# 闭包的使用
f = fOut(100) # f指向外部函数,返回的内部函数
print(type(f)) # f指向是一个函数类型
# 然后再调用内部函数
res = f(200) # 内部函数的返回结果
print("两个数的和: {}".format(res))
# 2. 使用闭包求两点之间的距离
# 传统函数
import math
def getDis(x1, y1, x2, y2):
return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
res = getDis(0, 0, 1, 1)
print("点(0,0)到点(1,1)的距离: {}".format(res))
# 使用闭包
def getDisOut(x1, y1):
def getDisIn(x2, y2):
return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
return getDisIn
f = getDisOut(0, 0)
res = f(1, 1) # 函数名加() 就是对函数的调用
print("点(0,0)到点(1,1)的距离: {}".format(res))
闭包的特殊用途,可以在不修改源代码的前提下,添加新的功能
# 闭包的特殊用途
# 闭包可以在不修改源代码的前提下,添加新的功能
# 例子: 添加日志功能
import time # 时间模块
def writeLog(func):
try:
# 以追加方式写入文件
file = open("writeLog.txt",'a',encoding='utf-8')
# 向文件写入日志信息 (访问: 方法名 时间: yyyy-MM-dd)
file.write("访问: {}\t".format(func.__name__))
file.write("时间: {}\n".format(time.asctime()))
except Exception as e:
print(e.args)
finally:
# 关闭资源都是在finally中关闭的
file.close()
def fun1():
# 这样已经修改了这个函数了
# writeLog(fun1)
print("功能1")
def fun2():
# 这样已经修改了这个函数了
# writeLog(fun2)
print("功能2")
# 使用闭包来实现
def fOut(func):
def fIn():
writeLog(func)
func()
return fIn
fIn1 = fOut(fun1)
fIn2 = fOut(fun2)
fIn1() # 进行函数调用
fIn2()
装饰器
在Python中,装饰器就是一种闭包,它可以使闭包的访问方式更简单
其实闭包就是先在内部函数中写要补充的部分,然后再调用一次原来的函数
装饰器的基本使用
# 使用装饰器就是让闭包的使用更加简单
# 使用装饰器完成不修改 fun1() fun2() 函数的源码,添加输出日志信息
import time
def writeLog(func):
try:
file = open("log.txt", "a", encoding="utf-8")
file.write("访问: {}\t".format(func.__name__))
file.write("时间: {}\n".format(time.asctime()))
except Exception as e:
print(e.args)
finally:
file.close()
# 定义闭包函数
def fOut(func):
def fIn():
writeLog(func)
# 这里对func()调用几次就是几次
# 如果没有对func()进行调用,函数直接结束
func()
func()
return fIn
# 使用装饰器在函数之前
# 就相当于把这个函数作为参数传入
# 装饰器装饰后,其实就是等价于 fIn = fOut(fun1),后面调用fun1(),就等同于fIn()
# 执行的是闭包的内容,由闭包来调用fun1
@fOut
def fun1():
print("功能1")
@fOut
def fun2():
print("功能2")
fun1()
fun2()
多个装饰器
# 给foo函数加上多个装饰器
def fOut1(func):
print("fOut1")
def fIn():
print("111111这是装饰器111111")
func()
print("111111这是装饰器111111")
return fIn
def fOut2(func):
print("fOut2")
def fIn():
print("222222这是装饰器222222")
func()
print("222222这是装饰器222222")
return fIn
# 重叠调用
# 是@fOut2先装饰的foo,然后@fOut1再装饰整个函数 => 理解清楚
@fOut1 # 这个@fOut1相当于最外层
@fOut2 # @fOut2为次外层
def foo(): # foo为最内层
print("foo()正在运行")
# 不调用函数,装饰器装饰的时候就调用了闭包的外部函数
# foo()
foo() # 现在是调用嵌套的内部函数
多个装饰器的执行顺序
带由参数的装饰器
如果只是参数的个数不同,使用可变参数 *args 解决
# 闭包如果是要装饰一个要传入参数的函数
# 则闭包的内部函数的参数与功能函数一致
# 使用可变参数 *args 来构建通用的装饰器
def fOut(func):
def fIn(*args):
# 有返回值的功能函数是需要return的
return func(*args)
return fIn
@fOut
def sum1(a, b):
return a + b
@fOut
def sum2(a, b, c):
return a + b + c
print(sum1(10, 20)) # 两个参数
print(sum2(10,20,30)) # 三个参数
偏函数
from functools import partial
1. Python 的`functools` 模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。
2. 偏函数是用于对函数固定属性的函数,作用就是把一个函数某些参数固定住(也就是设
置默认值),返回一个新的函数,调用这个新的函数会更简单。
# int() base vaild 2-36 => 看源码的注释
print(int("12345")) # 默认int就是10进制
print("转换为7进制:", int("12345", base=7))
# 偏函数就是来设置属性默认值的
from functools import partial
new_int = partial(int, base=2) # 这样就固定了base这个属性值
# 其实和自己写个函数是一致的
def my_int(s, base):
return int(s, base=base)