04 函数式编程

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})

猜你喜欢

转载自blog.csdn.net/qq_25672165/article/details/88839446