高阶python编程 - 函数式编程

高级python 函数式编程

  • 函数式

函数式编程(FunctionalProgramming)

  • 基于lambda演示得一种编程方式
    • 程序中只有函数
    • 函数可以做为参数,作为返回值,
    • 纯函数式编程语言 : LISP,Haskell
    • python函数式编程只是借鉴函数式编程得一些特点,可以理解成一半函数式一半python
    • 需要讲述
    • 高级函数 :把函数作为参数使用得函数,叫高级函数;
    • 返回函数 :把函数做为返回值得函数,叫返回函数;
    • 装饰器 :就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能;
    • 偏函数 :

lambda 表达式

  • 函数:最大程度复用代码
  • lambda表达式(匿名函数)
    • 一个表达式,没有方式名称
# 定义一个返回函数,返回fun2。通过变量fun进行接收返回值,打印返回值类型,并调用返回函数。
def fun(a):
    def fun2():
        print "this is fun2"
    print a
    return fun2
fun = fun(2)

print (type(fun))
print fun()

### 系统高阶函数 - map
- 原意就是映射,即把集合或列表得元素,每一个元素都按照一定规则进行操作,生成一个新的列表或者集合
- map函数是系统提供得具有映射功能得函数,返回值是一个迭代对象

  • map python2 传入什么类型数据返回什么类型数据
  • map python3 传入什么类型数据返回 …”map”… 类型数据

  • map(…)
    map(function, sequence[, sequence, …]) -> list

    Return a list of the results of applying the function to the items of
    the argument sequence(s). If more than one sequence is given, the
    function is called with an argument list consisting of the corresponding
    item of each sequence, substituting None for missing values when not all
    sequences have the same length. If the function is None, return a list of
    the items of the sequence (or a list of tuples if more than one sequence).

# map 举例
# 将一个列表中的元素乘以10,并得到新列表

l1 = [i for i in range(10)]
print(l1)
l2 = []
for i in l1:
    l2.append(i * 10)
print(l2)

# map 实现以上功能
def mulTen(n):
    return n * 10

l3 = map(mulTen,l1)
print (l3)

reduce

  • 意愿是归并,缩减
  • 把一个可迭代的对象最后归并成一个结果
  • 对于函数参数要求:必须有两个参数,必须有返回结果
  • reduce[1,2,3,4,5] = fun(fun(fun(fun(1,2),3),4),5)
  • reduce 需要 functools包
from functools import reduce

# 定义个操作函数

def add(x,y):
    return x + y

# 对于列表【1,2,3,4,5,6】执行add 操作
rst = reduce(add ,[1,2,3,4,5,6])
print (rst)
# 以上reduce可看作下面进行运算
rst2 =add(add(add(add(add(1,2),3),4),5),6)
print(rst2)

filter 函数

  • 过滤函数:对一组数据进行过滤,符合条件的数据会生成一个新的列表并返回
  • 跟map 相比:
    • 相同: 都对列表的每一个元素逐一进行操作
    • 不同: map会生成一个跟原来数据相对应的新队列
      filter 不一定,只要符合条件的才会进入新的数据集合
    • filter函数怎么写:
      • 利用给定函数进行判断
      • 返回值一定是个布尔值
      • 调用格式:filter(f,data),f是过滤函数,data是数据
# filter 函数
# 对一个列表,对其进行过滤,偶数组成一个新列表
# 需要定义过滤函数
# 过滤函数要求有输入,返回布尔值
def isEven(a):
    return a % 2 == 0
l = [1,2,3,4,54,3,2,32,32,32,3,333,44,32,4325]
res = filter(isEven,l)
#返回一个可迭代对象
print(res)
print([i for i in res])

高阶函数-排序

  • 把一个序列按照给定的算法进行排序
  • key: 在排序中对每一元素进行key函数运算,可以理解成按照key函数定义的逻辑进行排序
  • python2 和 python3 相差巨大
#排序案例1
a = [12,32,43,543,56,654,6576,5765,765,645,6546645,654645]
al = sorted(a)
ad = sorted(a,reverse=True)
print(al)
print(ad)
#排序案例2
a = [-12,2,32,-455,321,32]
# 按照绝对值进行排序
# abs是求绝对值的意思
# 即按照绝对值的倒叙进行排序
al = sorted(a, key=abs, reverse=True)

print(al)
#sorted 排序案例

astr = ['dana','whj','jin','WTt','Zs','sz']

str1 = sorted(astr)

print(str1)

str2 = sorted(astr,key=str.lower)

print(str2)

高阶函数-返回函数

# 负责一点的返回函数的例子
# args 参数列表
# myF4 定义函数,返回内部定义的函数myF5
# myF5使用了外部变量,这个变量是myF4的参数

def myF4( *args):
    def myF5():
        rst = 0
        for n in args:
            rst += n
        return rst
    return myF5

f5 = myF4(1,2,3,4,5,6,7,8,9,10)
f5()
f6 = myF4(10,20,30)
f6()

闭包(closure)

  • 当一个函数在内部定义函数,并且内部的函数应用外部函数的参数或局部变量,当内部函数被作返回值的时候,相关参数和变量保存在返回的函数中,这种结果,叫做闭包。
  • 上面定义的myF4 是一个标准的闭包结构
# 闭包常见的坑

def count():
    # 定义列表
    fs = []
    for i in range(1,4):
        # 定义了一个函数f
        def f():
            return i*i
        fs.append(f)
    return fs

f1,f2,f3 = count()
print(f1())
print(f2())
print(f3())

出现问题:

  • 造成上述情况的原因是,返回函数引用了变量i,i并非立即执行,而是等到三个函数都返回的时候才统一执行,此时i已经变成了3,最终调用的时候,都返回的3*3
  • 此问题描述成:返回闭包时,返回函数不能引用任何循环变量
  • 解决方案:在创建一个函数,用该函数的参数绑定循环变量的当前值,无论该循环变量以后如何改变,已经绑定的函数参数值不在改变
# 修改上述函数

def count1():
    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 = count1()
print(f1())
print(f2())
print(f3)

装饰器(Dercrator)

  • python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数
  • 在不改动函数代码的基础上无限制扩展函数功能的一种机制,本质上讲,装饰器是一个返回函数的高阶函数
  • 装饰器使用:使用@语法,即在每次要扩展到函数定义前面使用@+函数名
  • 装饰器先执行装饰器内函数,在执行被装饰函数。
# 我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修改,例如:
import time
def hello():
    startTime = time.time()
    print("hello")
    time.sleep(1)
    print("world")
    endTime = time.time()
    msecs = (endTime - startTime)*1000
    print("time is %d ms" %msecs)

hello()
  • 避免直接侵入原函数修改,但是生效需要再次执行函数
import time

def deco(func):
    startTime = time.time()
    func()
    endTime = time.time()
    msecs = (endTime - startTime)*1000
    print("time is %d ms" %msecs)

def func():
    print("hello")
    time.sleep(1)
    print("world")


f = func
deco(f)#只有把func()或者f()作为参数执行,新加入功能才会生效
  • 核心代码区域有一千万个func()函数,从func01()到func1kw(),按以上实现方案,想要拓展这一千万个函数功能,就是要执行一千万次deco()函数。这种方式不可取。
  • 实现一个最简陋的装饰器,不使用任何语法和高级语法,看看装饰器最原始的面貌
  • 这里的deco函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数func()就在返回函数wrapper()的内部执行。然后在函数func()前面加上@deco,func()函数就相当于被注入了计时功能,现在只要调用func(),它就已经变身为“新的功能更多”的函数了。
  • 所以这里装饰器就像一个注入符号:拓展了原来函数的功能既不需要侵入函数内更改代码,也不需要重复执行原函数。
#既不需要侵入,也不需要函数重复执行
import time
def deco(func):
    def wrapper():
        startTime = time.time()
        func()
        endTime = time.time()
        msecs = (endTime - startTime)*1000
        print("time is %d ms" %msecs)
    return wrapper
# 上面定义装饰器,使用的时候需要用到@ ,此符号是python的语法糖
@deco
def func():
    print("hello")
    time.sleep(1)
    print("world")


f = func #这里f被赋值为func,执行f()就是执行func()
f()
  • 带有参数的装饰器
import time

def deco(func):
    def wrapper(a,b):
        startTime = time.time()
        func(a,b)
        endTime = time.time()
        msecs = (endTime - startTime)*1000
        print("time is %d ms" %msecs)
    return wrapper

@deco
def func(a,b):
    print("hello,here is a func for add :")
    time.sleep(1)
    print("result is %d" %(a+b))


f = func
f(3,4)
  • 带有不定参数的装饰器
import time

def deco(func):
    def wrapper(*args, **kwargs):
        startTime = time.time()
        func(*args, **kwargs)
        endTime = time.time()
        msecs = (endTime - startTime)*1000
        print("time is %d ms" %msecs)
    return wrapper

@deco
def func(a,b):
    print("hello,here is a func for add :")
    time.sleep(1)
    print("result is %d" %(a+b))

@deco
def func2(a,b,c):
    print("hello,here is a func for add :")
    time.sleep(1)
    print("result is %d" %(a+b+c))

f = func
func2(3,4,5)
f(3,4)
  • 多个装饰器
import time

def deco01(func):
    def wrapper(*args, **kwargs):
        print("this is deco01")
        startTime = time.time()
        func(*args, **kwargs)
        endTime = time.time()
        msecs = (endTime - startTime)*1000
        print("time is %d ms" %msecs)
        print("deco01 end here")
    return wrapper

def deco02(func):
    def wrapper(*args, **kwargs):
        print("this is deco02")
        func(*args, **kwargs)
        print("deco02 end here")
    return wrapper

@deco01
@deco02
def func(a,b):
    print("hello,here is a func for add :")
    time.sleep(1)
    print("result is %d" %(a+b))

f = func
f(3,4)

偏函数(Partial)

  • 参数固定的函数,相当于一个由特定参数的函数体
  • functools.partial的作用是:把一个函数某些函数固定,返回一个新函数
# 把字符串转换十进制数字

int("12345")

# 求八进制的字符串12345,表示成十进制的数字是多少

int("12345",base=8)
# 新建一个函数,此函数是默认输入的字符串是16进制数字
# 把此字符串返回十进制的数字

def int16(x,base=16):
    return int(x,base)

int16("12345")

import functools
int16 = functools.partial(int,base=16)
int16("12345")

猜你喜欢

转载自blog.csdn.net/july_whj/article/details/80845789