浅谈Python 函数式编程

匿名函数lambda表达式

什么是匿名函数?

匿名函数,顾名思义就是没有名字的函数,在程序中不用使用 def 进行定义,可以直接使用 lambda 关键字编写简单的代码逻辑。lambda 本质上是一个函数对象,可以将其赋值给另一个变量,再由该变量来调用函数,也可以直接使用。

#平时,我们是先定义函数,再进行调用
def power(x):
  return x ** 2

print(power(2))

#使用lambda表达式的时候,我们可以这样操作
power = lambda x : x ** 2
print(power(2))

#觉得太麻烦,还可以这样调用
print((lambda x: 2 * x)(8))

lambda表达式的基本格式:lambda 入参 : 表达式

#入参可以有多个,比如
power = lambda x, n: x ** n

print(power(2, 3))

lambda 表达式的使用场景

一般适用于创建一些临时性的,小巧的函数。比如上面的 power函数,我们当然可以使用 def 来定义,但使用 lambda 来创建会显得很简洁,尤其是在高阶函数的使用中。

定义一个函数,传入一个list,将list每个元素的值加1

def add(l = []):
  return [x +1 for x in l]

print(add([1,2,3]))

上面的函数改成将所有元素的值加2

可能大家会说,这还不简单,直接把return里的1改成2就行了。但是真的行吗?如果函数被多个地方使用,而其他地方并不想加2,怎么办?

这好办,把变得那部分抽出来,让调用者自己传

def add(func,l = []):
  return [func(x) for x in l]

def add1(x):
  return x+1

def add2(x):
  return x+2

print(add(add1,[1,2,3]))
print(add(add2,[1,2,3]))

一个简简单单的问题,一定要用这么多代码实现?

def add(func,l = []):
  return [func(x) for x in l]

print(add(lambda x:x+1,[1,2,3]))
print(add(lambda x:x+2,[1,2,3]))

map函数

map的基本格式

map(func, *iterables)

map() 函数接收两个以上的参数,开头一个是函数,剩下的是序列,将传入的函数依次作用到序列的每个元素,并把结果作为新的序列返回。也就是类似 map(func,[1,2,3])

同样的,我们还是来完成这样一个功能:将list每个元素的值加1

def add(x):
  return x + 1

result = map(add, [1, 2, 3, 4])
print(type(result))
print(list(result))

使用lambda表达式简化操作

result = map(lambda x: x + 1, [1, 2, 3, 4])
print(type(result))
print(list(result))

函数中带两个参数的map函数格式

使用map函数,将两个序列的数据对应位置求和,之后返回,也就是对[1,2,3],[4,5,6]两个序列进行操作之后,返回结果[5,7,9]

print(list(map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6])))

对于两个序列元素个数一样的,相对好理解。如果两个序列个数不一样的,会不会报错?

print(list(map(lambda x, y: x + y, [1, 2, 3], [4, 5])))

我们可以看到不会报错,但是结果以个数少的为准

reduce函数

reduce函数的基本格式

reduce(function, sequence, initial=None)

reduce把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce函数把结果继续和序列的下一个元素做累积计算,跟递归有点类似,reduce函数会被上一个计算结果应用到本次计算中

reduce(func, [1,2,3]) = func(func(1, 2), 3)

使用reduce函数,计算一个列表的乘积

from functools import reduce

def func(x, y):
  return x * y

print(reduce(func, [1, 2, 3, 4]))

结合lambda表达式,简化操作

from functools import reduce

print(reduce(lambda x, y: x * y, [1, 2, 3, 4]))

filter 函数

filter 顾名思义是过滤的意思,带有杂质的(非需要的数据),经过 filter 处理之后,就被过滤掉。

filter函数的基本格式

filter(function_or_None, iterable)

filter() 接收一个函数和一个序列。把传入的函数依次作用于每个元素,然后根据返回值是 True 还是 False 决定保留还是丢弃该元素。

使用 filter 函数对给定序列进行操作,最后返回序列中所有偶数

print(list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4, 5])))

sorted 函数

sorted从字面上就可以看去这是个用来排序的函数,sorted 可以对所有可迭代的对象进行排序操作

sorted的基本格式

sorted(iterable, key=None, reverse=False)

#iterable -- 可迭代对象。
#key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
#reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。 

#对序列做升序排序
print(sorted([1, 6, 4, 5, 9]))

#对序列做降序排序
print(sorted([1, 6, 4, 5, 9], reverse=True))

#对存储多个列表的列表做排序
data = [["Python", 99], ["c", 88]]
print(sorted(data, key=lambda item: item[1]))

闭包

在万物皆对象的Python中,函数是否能作为函数的返回值进行返回呢?

def my_power():
  n = 2
  def power(x):
    return x ** n
  return power

p = my_power()
print(p(4))

#------------------------------------------------------------
def my_power():
  n = 2
  def power(x):
    return x ** n
  return power

n = 3
p = my_power()
print(p(4))

我们可以看到,my_power 函数在返回的时候,也将其引用的值(n)一同带回,n 的值被新的函数所使用,这种情况我们称之为闭包

当我们把n的值移除到my_power函数外面,这个时候来看下计算结果

n = 2

def my_power():
  def power(x):
    return x ** n
  return power

n = 3
p = my_power()
print(p(4))

为什么输出的结果会是64?

我们先来看看闭包时,p.__closure____的结果

#例1
def my_power():
  n = 2
  def power(x):
    return x ** n
  return power

p = my_power()
print(p.__closure__)

#结果:(<cell at 0x00000264518F9A38: int object at 0x00007FFA7F617120>)
#closure是内部函数的一个属性,用来保存环境变量

#---------------------------------------------------------------------

#例2
n = 2
def my_power():
  def power(x):
    return x ** n
  return power

n = 3
p = my_power()
print(p.__closure__)

#输出结果 None

通过例1跟例2对比,我们可以知道,例2并不是闭包

闭包经典问题

下面的程序是否是闭包?能否正确运行

def my_power():
  n = 2

  def power(x):
    n += 1
    return x ** n

  return power

p = my_power()
print(p(3))

如何让上面的程序正确运行?看看改正之后的结果

def my_power():
  n = 2

  def power(x):
    nonlocal n
    n += 1
    return x ** n

  return power

p = my_power()
print(p.__closure__)
print(p(3))
print(p(3))

看看下面的程序的运行结果

def my_power():
  n = 2
  L = []
  for i in range(1, 3):
    def power():
      return i ** n

    L.append(power)
  return L

f1, f2 = my_power()
print(f1())
print(f2())
print(f1.__closure__[0].cell_contents)
print(f2.__closure__[0].cell_contents)

python的函数只有在执行时,才会去找函数体里的变量的值,也就是说你连形参都不确定,你咋求知道 i为几呢?在这里,你只需要记住如果你连形参都不确定,python就只会记住最后一个i值。

装饰器及其应用

什么是装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

import time

start = time.time()
time.sleep(4)
end = time.time()
print(end - start)

从实际例子来看装饰器

def my_fun():
  print("这是一个函数")

my_fun()

要再打印“这是一个函数”前面在打印多一行hello world。

def my_fun():
  begin = time.time()
  time.sleep(2)
  print("这里一个函数")
  end = time.time()
  print(end-begin)

my_fun()

这个时候,如果不想修改原有的函数,咋整?

def my_fun():
  print("这是一个函数")

def my_time(func):
  begin = time.time()
  time.sleep(2)
  func()
  end = time.time()
  print(end - begin)

my_time(func)

这种方式,因为要增加功能,导致所有的业务调用方都得进行修改,此法明显不可取。

另一种方式:

def print_cost(func):
  def wrapper():
    begin = time.time()
    time.sleep(2)
    func()
    end = time.time()
    print(end - begin)
    return wrapper

@print_cost
def my_fun():
  print("这里一个函数")

第二种方式并没有修改func函数的内部实现,而是使用装饰器模式对其功能进行装饰增强。

以上就是浅谈Python 函数式编程的详细内容,更多关于Python 函数式编程的资料请关注我们其它相关文章!

(0)

相关推荐

  • Python中的函数式编程:不可变的数据结构

    让我们首先考虑正方形和长方形.如果我们认为在接口方面,忽略了实现细节,方块是否是矩形的子类型? 子类型的定义取决于Liskov代换原理.为了成为一个子类型,它必须能够完成超级类型所做的一切. 如何定义矩形的接口? zope.interface import Interface class IRectangleInterface: get_length: """Squares can do that""" get_width: "&quo

  • 详解Python函数式编程—高阶函数

    函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用.而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的. 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数! Python对函数式编程提供部分支持.由于Python允许使用变量,因此,Python不是纯函数式编程语言. 高阶函数 变量

  • Python函数式编程

    主要内容 1.函数基本语法及特性 2.参数与局部变 3.返回值 4.递归 5.名函数 6.函数式编程介绍 7.阶函数 8.内置函数 函数基本语法及特性 定义 数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一 个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变 量,y是x的函数.自变量x的取值范围叫做这个函数的定义域. 但编程中的「函数」概念,与数学中的函数是有很 同的 函数是逻辑结构化和过程化的一种编程方法 函数的优点 减少重复代码 使程

  • Python3中lambda表达式与函数式编程讲解

    简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数.其一般有如下几种使用方式: 1.lambda的一般形式是关键字lambda后面跟一个或多个参数,紧跟一个冒号,以后是一个表达式.lambda是一个表达式而不是一个语句.它能够出现在Python语法不允许def出现的地方.作为表达式,lambda返回一个值(即一个新的函数).lambda用来编写简单的函数,而def用来处理更强大的任务.例如: f = lambda x,y

  • 使用Python的toolz库开始函数式编程的方法

    在这个由两部分组成的系列文章的第二部分中,我们将继续探索如何将函数式编程方法中的好想法引入到 Python中,以实现两全其美. 在上一篇文章中,我们介绍了不可变数据结构 . 这些数据结构使得我们可以编写"纯"函数,或者说是没有副作用的函数,仅仅接受一些参数并返回结果,同时保持良好的性能. 在这篇文章中,我们使用 toolz 库来构建. 这个库具有操作此类函数的函数,并且它们在纯函数中表现得特别好. 在函数式编程世界中,它们通常被称为"高阶函数",因为它们将函数作为参

  • Python编程中对super函数的正确理解和用法解析

    当在子类需要调用父类的方法时,在python2.2之前,直接用类名调用类的方法,即非绑定的类方法,并把自身对象self作参数传进去. class A(object): def say(self): print 'I am A' class B(A): def say(self): print 'I am B' A.say(self) b = B() b.say() 输出 I am B I am A 这样运作挺好,不过有个问题,当父类改了名字时,就要把这些显式调用父类的一个个更正,子类和父类耦合比

  • Python编程之Re模块下的函数介绍

    re模块下的函数 compile(pattern):创建模式对象 import re pat=re.compile('A') m=pat.search('CBA') #等价于 re.search('A','CBA') print m <_sre.SRE_Match object at 0x9d690c8> #匹配到了,返回MatchObject(True) m=pat.search('CBD') print m None #没有匹配到,返回None(False) search(pattern,

  • python网络编程调用recv函数完整接收数据的三种方法

    最近在使用python进行网络编程开发一个通用的tcpclient测试小工具.在使用socket进行网络编程中,如何判定对端发送一条报文是否接收完成,是进行socket网络开发必须要考虑的一个问题.这里,简要介绍一下判别数据接收接收完成常用的三种方法: 1.基础数据接收法: 使用基础数据接收法时,当与服务socket断开连接时,会接收到空字符串.因此,可以根据此特点,在程序中加入循环,一直接收数据,直到数据发送端关闭socket连接.适用场景:客户端和服务器的链接为短链接(即一次socket通讯

  • Python编程快速上手——strip()函数的正则表达式实现方法分析

    本文实例讲述了Python strip()函数的正则表达式实现方法.分享给大家供大家参考,具体如下: 题目如下: 写一个函数,它接受一个字符串,做的事情和strip()字符串方法一样.如果只传入要去除的字符串(原字符串),没有其他参数,那么就从该字符串首尾去除空白字符串.否则,函数第二个参数指定的字符串将从该字符串中去除 思路如下: 补充:字符串的str.strip()方法,去除字符串首尾指定的字符,只能去除头尾两边,不能去除中间 程序需要做以下的事情: 接受一个字符串和要去除的字符 调用函数去

  • Python函数式编程指南:对生成器全面讲解

    生成器是迭代器,同时也并不仅仅是迭代器,不过迭代器之外的用途实在是不多,所以我们可以大声地说:生成器提供了非常方便的自定义迭代器的途径. 这是函数式编程指南的最后一篇,似乎拖了一个星期才写好,嗯-- 1. 生成器(generator) 1.1. 生成器简介 首先请确信,生成器就是一种迭代器.生成器拥有next方法并且行为与迭代器完全相同,这意味着生成器也可以用于Python的for循环中.另外,对于生成器的特殊语法支持使得编写一个生成器比自定义一个常规的迭代器要简单不少,所以生成器也是最常用到的

  • Python函数式编程实例详解

    本文实例讲述了Python函数式编程.分享给大家供大家参考,具体如下: 函数式编程就是一种抽象程度很高的编程范式,从计算机硬件->汇编语言->C语言->Python抽象程度越高.越贴近于计算,但执行效率也越低.纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用.而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的.函数式编程的一个特点就是,允许把函数

随机推荐