1. 函数式编程(FunctionalProgramming)
- 基于lambda演算的一种编程方式
- 程序中只有函数
- 函数可以作为参数,同样可以作为返回值
- 纯函数式编程语言: LISP, Haskell
- Python函数式编程只是借鉴函数式编程的一些特点,可以理解成一半函数式一半Python
2. lambda表达式
-
函数: 最大程度复用代码
- 存在问题: 如果函数很小,很短,则会造成啰嗦
- 如果函数被调用次数少,则会造成浪费
- 对于阅读者来说,造成阅读流程的被迫中断
-
lambda表达式(匿名函数):
- 一个表达式,函数体相对简单
- 不是一个代码块,仅仅是一个表达式
- 可以有参数,有多个参数也可以,用逗号隔开
# lambda表达式的用法
1. 以lambda开头
# 2. 紧跟一定的参数(如果有的话)
# 3. 参数后用冒号和表达式主题隔开
# 4. 只是一个表达式,所以,没有return
num = lambda x,y,z: x * 100 + y * 10 + z
s = num(1,2,3)
print(s)
>123
3. 高阶函数
- 把函数作为参数使用的函数,叫高阶函数
##定义函数需要扩大100倍
def funA(n):
return n * 100
##定义函数需要扩大300倍
def funB(n, f):
# 假定函数是把n扩大100被
return f(n) * 3
print( funB(9, funA) )
>2700
- 高阶函数-map
- 原意就是映射,即把集合或者列表的元素,每一个元素都按照一定规则进行操作,生成一个新的列表或者集合
- map函数是系统提供的具有映射功能的函数,返回值是一个迭代对象
- 语法:map(func, *iterables) --> map object
def f(x):
return x * x
l = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
for i in l:
print(i,end=' ')
>1 4 9 16 25 36 49 64 81
- 高阶函数-reduce
- 原意是归并,缩减,把一个可迭代对象最后归并成一个结果
- 对于作为参数的函数要求: 必须由两个参数,必须由返回结果
- reduce([1,2,3,4,5]) == f(f(f(f(1,2),3),4),5)
- python3中使用reduce需要导入functools包
from functools import reduce
def add(m,n):
return m + n
l = reduce(add,[1,2,3,4,5,6])
print(l)
>21
- 高阶函数-filter 函数
- 过滤函数: 对一组数据进行过滤,符合条件的数据会生成一个新的列表并返回
- 跟map相比较:
- 相同:都对列表的每一个元素逐一进行操作
- 不同:
- map会生成一个跟原来数据想对应的新队列
- filter不一定,只要符合条件的才会进入新的数据集合
- filter函数怎么写:
- 利用给定函数进行判断
- 返回值一定是个布尔值
- 调用格式: filter(f, data), f是过滤函数, data是数据
# 对于一个列表,对其进行过滤,偶数组成一个新列表
# 需要定义过滤函数要求有输入,返回布尔值
def isEven(a):
return a % 2 == 0
l = [3,4,56,3,2,3,4556,67,4,4,3,23455,43]
rst = filter(isEven, l)
# 返回的filter内容是一个可迭代对象
print(type(rst))
print(rst)
print([i for i in rst])
><class 'filter'>
<filter object at 0x007C1710>
[4, 56, 2, 4556, 4, 4]
- 高阶函数-排序
- 把一个序列按照给定算法进行排序
- key: 在排序钱对每一个元素进行key函数运算,可以理解成按照key函数定义的逻辑进行排序
- 语法:sorted(iterable, /, *, key=None, reverse=False)
a = [-43,23,45,6,-23,2,-4345]
b = sorted(a,key= abs,reverse=True)
print(b)
>[-4345, 45, -43, 23, -23, 6, 2]
3. 返回函数
- 函数可以返回具体的值
- 也可以返回一个函数作为结果
# 函数作为返回值返回, 被返回的函数在函数体内定义
def myFun1():
def myFun2():
print('In myFun2')
return 2
return myFun2
a = myFun1()
print(type(a))
print(a)
a()
><class 'function'>
<function myFun1.<locals>.myFun2 at 0x01386390>
In myFun2
--------------------------------------------------------------
def myFun3(*args):
def myFun4():
sum = 0
for i in args:
sum += i
return sum
return myFun4()
b = myFun3(1,2,3,4,5,6,7,8,9)
print(b)
>4950
- 闭包(closure)
- 当一个函数在内部定义函数,并且内部的函数应用外部函数的参数或者局部变量,当内部函数被当做返回值的时候,相关参数和变量保存在返回的函数中,这种结果,叫闭包
# 闭包常见坑
def count():
# 定义列表,列表里存放的是定义的函数
fs = []
for i in range(1,4):
# 定义了一个函数f
# f是一个闭包结构
def f():
return i*i
fs.append(f)
return fs
f1,f2,f3 = count()
print(f1())
print(f2())
print(f3())
>9
9
9
- 出现的问题:
- 造成上述状况的原因是,返回函数引用了变量i, i并非立即执行,而是等到三个函数都返回的时候才统一使用,此时i已经变成了3,最终调用的时候,都返回的是 3*3
- 此问题描述成:返回闭包时,返回函数不能引用任何循环变量
- 解决方案: 再创建一个函数,用该函数的参数绑定循环变量的当前值,无论该循环变量以后如何改变,已经绑定的函数参数值不再改变
# 修改上述函数
def count2():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1,4):
fs.append(f(i))
return fs
f1,f2,f3 = count2()
print(f1())
print(f2())
print(f3())
>1
4
9
4. 装饰器
- 在不改动函数代码的基础上无限制扩展函数功能的一种机制,本质上讲,装饰器是一个返回函数的高阶函数
- 装饰器的使用: 使用@语法, 即在每次要扩展到函数定义前使用@+函数名
- 好处:一点定义,则可以装饰任意函数,且把装饰器的功能直接添加到定义函数的功能上
def hello():
print("Hello world")
# 调用
hello()
# 复制给函数f,并掉用
f = hello
f()
## f 和hello是一个函数
print(id(hello))
print(id(f))
print(hello.__name__)
print(f.__name__)
>Hello world
Hello world
10160216
10160216
hello
hello
---------------------------------------------------------------
def hello(f):
def word(*args, **kwargs):
print("Hello everyone,Good morning!")
return f(*args, **kwargs)
return word
@hello
def weekday():
print('Today is Wednesday')
weekday()
@hello
def weather():
print('Today in fine!')
weather()
>Hello everyone,Good morning!
Today is Wednesday
>Hello everyone,Good morning!
Today in fine!
- 装饰器手动执行示例
##手动执行
def hello(f):
def word(*args, **kwargs):
print("Hello everyone,Good morning!")
return f(*args, **kwargs)
return word
def weekday():
print('Today is Wednesday')
a = hello(weekday)
a()
>Hello everyone,Good morning!
Today is Wednesday
5. 偏函数
- 参数固定的函数,相当于一个由特定参数的函数体
- functools.partial的作用是,把一个函数某些函数固定,返回一个新函数,方便调用
import functools
int16 = functools.partial(int,base = 16)
print(int(234324))
print(int16('234324'))
>234324
>2310948
6. 高阶函数补充
- zip
- 把两个可迭代内容生成一个可迭代的tuple元素类型组成的内容
z1 = [1,2,3,4,5,6]
z2 = [11,22,33,44,55,66]
z = zip(z1,z2)
print(type(z))
print(z)
z0 = [i for i in z]
print(z0)
><class 'zip'>
<zip object at 0x00AF8DF0>
[(1, 11), (2, 22), (3, 33), (4, 44), (5, 55), (6, 66)]
- enumerate
- 跟zip功能比较像
- 对可迭代对象里的每一元素,配上一个索引,然后索引和内容构成tuple类型
l1 = [11,22,33,44,55]
em = enumerate(l1,start=200)
l2 = [i for i in em]
print(l2)</pre>
>[(200, 11), (201, 22), (202, 33), (203, 44), (204, 55)]
- collections模块-----namedtuple
- tuple类型,是一个可命名的tuple
import collections
a = collections.namedtuple('b',['x','y'])
c = a(1,2)
print(c.x)
print(c[0])
d = c.x + c.y
print(d)
>1
1
3
- collections模块-----deque
- 比较方便的解决了频繁删除插入带来的效率问题
from collections import deque
q = deque(['a', 'b', 'c'])
print(q)
q.append("d")
print(q)
q.appendleft('x')
print(q)
>deque(['a', 'b', 'c'])
deque(['a', 'b', 'c', 'd'])
deque(['x', 'a', 'b', 'c', 'd'])
- collections模块-----defaultdict
- 当直接读取dict不存在的属性时,直接返回默认值
from collections import defaultdict
func = lambda :'该键值对不存在,返回默认值替代"KeyError"'
a = defaultdict(func)
a['one'] = 1
a['two'] = 2
print(a['one'])
print(a['three'])
>1
该键值对不存在,返回默认值替代"KeyError"
- collections模块-----Counter
- 统计字符串个数
from collections import Counter
a = Counter('weqweqfsdvfsdgrdthdgbhdtsdfs')
print(a)
>Counter({'d': 6, 's': 4, 'f': 3, 'w': 2, 'e': 2, 'q': 2, 'g': 2, 't': 2, 'h': 2, 'v': 1, 'r': 1, 'b': 1})