Python函数式编程指南(二):函数

【半导体先进工艺制程技术系列】HKMG工艺:金属栅极的“雕刻”艺术与性能博弈 本文深入解析HKMG工艺在半导体先进制程中的关键作用,详细介绍了金属栅极的精密制造流程与性能优化策略。通过原子级精度的材料堆叠和工艺创新,HKMG技术显著提升芯片性能与能效,成为28nm节点后的行业标配。文章还探讨了该工艺面临的物理极限及未来演进方向,为半导体制造领域提供重要参考。 阅读详情

作者:AstralWind

原文地址:http://www.cnblogs.com/huxi/archive/2011/06/24/2089358.html

2. 从函数开始
2.1. 定义一个函数

如下定义了一个求和函数:

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

关于参数和返回值的语法细节可以参考其他文档,这里就略过了。

使用lambda可以定义简单的单行匿名函数。lambda的语法是:

lambda args: expression

参数(args)的语法与普通函数一样,同时表达式(expression)的值就是匿名函数调用的返回值;而lambda表达式返回这个匿名函数。如果我们给匿名函数取个名字,就像这样:

lambda_add = lambda x, y: x + y

这与使用def定义的求和函数完全一样,可以使用lambda_add作为函数名进行调用。然而,提供lambda的目的是为了编写偶尔为之的、简单的、可预见不会被修改的匿名函数。这种风格虽然看起来很酷,但并不是一个好主意,特别是当某一天需要对它进行扩充,再也无法用一个表达式写完时。如果一开始就需要给函数命名,应该始终使用def关键字。

2.2. 使用函数赋值

事实上你已经见过了,上一节中我们将lambda表达式赋值给了add。同样,使用def定义的函数也可以赋值,相当于为函数取了一个别名,并且可以使用这个别名调用函数:

add_a_number_to_another_one_by_using_plus_operator = add
print add_a_number_to_another_one_by_using_plus_operator(1, 2)

既然函数可以被变量引用,那么将函数作为参数和返回值就是很寻常的做法了。

2.3. 闭包

闭包是一类特殊的函数。如果一个函数定义在另一个函数的作用域中,并且函数中引用了外部函数的局部变量,那么这个函数就是一个闭包。下面的代码定义了一个闭包:

def f():
    n = 1
    def inner():
        print n
    inner()
    n = 'x'
    inner()

函数inner定义在f的作用域中,并且在inner中使用了f中的局部变量n,这就构成了一个闭包。闭包绑定了外部的变量,所以调用函数f的结果是打印1和'x'。这类似于普通的模块函数和模块中定义的全局变量的关系:修改外部变量能影响内部作用域中的值,而在内部作用域中定义同名变量则将遮蔽(隐藏)外部变量。

如果需要在函数中修改全局变量,可以使用关键字global修饰变量名。Python 2.x中没有关键字为在闭包中修改外部变量提供支持,在3.x中,关键字nonlocal可以做到这一点:

#Python 3.x supports `nonlocal'
def f():
    n = 1
    def inner():
        nonlocal n
        n = 'x'
    print(n)
    inner()
    print(n)

调用这个函数的结果是打印1和'x',如果你有一个Python 3.x的解释器,可以试着运行一下。

由于使用了函数体外定义的变量,看起来闭包似乎违反了函数式风格的规则即不依赖外部状态。但是由于闭包绑定的是外部函数的局部变量,而一旦离开外部函数作用域,这些局部变量将无法再从外部访问;另外闭包还有一个重要的特性,每次执行至闭包定义处时都会构造一个新的闭包,这个特性使得旧的闭包绑定的变量不会随第二次调用外部函数而更改。所以闭包实际上不会被外部状态影响,完全符合函数式风格的要求。(这里有一个特例,Python 3.x中,如果同一个作用域中定义了两个闭包,由于可以修改外部变量,他们可以相互影响。)

虽然闭包只有在作为参数和返回值时才能发挥它的真正威力,但闭包的支持仍然大大提升了生产率。

2.4. 作为参数

如果你对OOP的模板方法模式很熟悉,相信你能很快速地学会将函数当作参数传递。两者大体是一致的,只是在这里,我们传递的是函数本身而不再是实现了某个接口的对象。 
我们先来给前面定义的求和函数add热热身:

print add('三角形的树', '北极')

与加法运算符不同,你一定很惊讶于答案是'三角函数'。这是一个内置的彩蛋...bazinga!

言归正传。我们的客户有一个从0到4的列表:

lst = range(5) #[0, 1, 2, 3, 4]

虽然我们在上一小节里给了他一个加法器,但现在他仍然在为如何计算这个列表所有元素的和而苦恼。当然,对我们而言这个任务轻松极了:

amount = 0
for num in lst:
    amount = add(amount, num)

这是一段典型的指令式风格的代码,一点问题都没有,肯定可以得到正确的结果。现在,让我们试着用函数式的风格重构一下。

首先可以预见的是求和这个动作是非常常见的,如果我们把这个动作抽象成一个单独的函数,以后需要对另一个列表求和时,就不必再写一遍这个套路了:

def sum_(lst):
    amount = 0
    for num in lst:
        amount = add(amount, num)
    return amount
 
print sum_(lst)

还能继续。sum_函数定义了这样一种流程: 
1. 使用初始值与列表的第一个元素相加; 
2. 使用上一次相加的结果与列表的下一个元素相加; 
3. 重复第二步,直到列表中没有更多元素; 
4. 将最后一次相加的结果返回。

如果现在需要求乘积,我们可以写出类似的流程——只需要把相加换成相乘就可以了:

def multiply(lst):
    product = 1
    for num in lst:
        product = product * num
    return product

除了初始值换成了1以及函数add换成了乘法运算符,其他的代码全部都是冗余的。我们为什么不把这个流程抽象出来,而将加法、乘法或者其他的函数作为参数传入呢?

def reduce_(function, lst, initial):
    result = initial
    for num in lst:
        result = function(result, num)
    return result
 
print reduce_(add, lst, 0)

现在,想要算出乘积,可以这样做:

print reduce_(lambda x, y: x * y, lst, 1)

那么,如果想要利用reduce_找出列表中的最大值,应该怎么做呢?请自行思考:)

虽然有模板方法这样的设计模式,但那样的复杂度往往使人们更情愿到处编写循环。将函数作为参数完全避开了模板方法的复杂度。

Python有一个内建函数reduce,完整实现并扩展了reduce_的功能。本文稍后的部分包含了有用的内建函数的介绍。请注意我们的目的是没有循环,使用函数替代循环是函数式风格区别于指令式风格的最显而易见的特征。

*像Python这样构建于类C语言之上的函数式语言,由于语言本身提供了编写循环代码的能力,内置函数虽然提供函数式编程的接口,但一般在内部还是使用循环实现的。同样的,如果发现内建函数无法满足你的循环需求,不妨也封装它,并提供一个接口。

2.5. 作为返回值

将函数返回通常需要与闭包一起使用(即返回一个闭包)才能发挥威力。我们先看一个函数的定义:

def map_(function, lst):
    result = []
    for item in lst:
        result.append(function(item))
    return result

函数map_封装了最常见的一种迭代:对列表中的每个元素调用一个函数。map_需要一个函数参数,并将每次调用的结果保存在一个列表中返回。这是指令式的做法,当你知道了列表解析(list comprehension)后,会有更好的实现。

这里我们先略过map_的蹩脚实现而只关注它的功能。对于上一节中的lst,你可能发现最后求乘积结果始终是0,因为lst中包含了0。为了让结果看起来足够大,我们来使用map_为lst中的每个元素加1:

lst = map_(lambda x: add(1, x), lst)
print reduce_(lambda x, y: x * y, lst, 1)

答案是120,这还远远不够大。再来:

lst = map_(lambda x: add(10, x), lst)
print reduce_(lambda x, y: x * y, lst, 1)

囧,事实上我真的没有想到答案会是360360,我发誓没有收周鸿祎任何好处。

现在回头看看我们写的两个lambda表达式:相似度超过90%,绝对可以使用抄袭来形容。而问题不在于抄袭,在于多写了很多字符有木有?如果有一个函数,根据你指定的左操作数,能生成一个加法函数,用起来就像这样:

lst = map_(add_to(10), lst) #add_to(10)返回一个函数,这个函数接受一个参数并加上10后返回

写起来应该会舒服不少。下面是函数add_to的实现:

def add_to(n):
    return lambda x: add(n, x)

通过为已经存在的某个函数指定数个参数,生成一个新的函数,这个函数只需要传入剩余未指定的参数就能实现原函数的全部功能,这被称为偏函数。Python内置的functools模块提供了一个函数partial,可以为任意函数生成偏函数:

functools.partial(func[, *args][, **keywords])

你需要指定要生成偏函数的函数、并且指定数个参数或者命名参数,然后partial将返回这个偏函数;不过严格的说partial返回的不是函数,而是一个像函数一样可直接调用的对象,当然,这不会影响它的功能。

另外一个特殊的例子是装饰器。装饰器用于增强甚至干脆改变原函数的功能,我曾写过一篇文档介绍装饰器,地址在这里:http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html。

*题外话,单就例子中的这个功能而言,在一些其他的函数式语言中(例如Scala)可以使用名为柯里化(Currying)的技术实现得更优雅。柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。如下的伪代码所示:

#不是真实的代码
def add(x)(y): #柯里化
    return x + y
 
lst = map_(add(10), lst)

通过将add函数柯里化,使得add接受第一个参数x,并返回一个接受第二个参数y的函数,调用该函数与前文中的add_to完全相同(返回x + y),且不再需要定义add_to。看上去是不是更加清爽呢?遗憾的是Python并不支持柯里化。

2.6. 部分内建函数介绍
  • reduce(function, iterable[, initializer]) 
    这个函数的主要功能与我们定义的reduce_相同。需要补充两点: 
    它的第二个参数可以是任何可迭代的对象(实现了__iter__()方法的对象); 
    如果不指定第三个参数,则第一次调用function将使用iterable的前两个元素作为参数。 
    由reduce和一些常见的function组合成了下面列出来的内置函数(+_+):
    all(iterable) == reduce(lambda x, y: bool(x and y), iterable)
    any(iterable) == reduce(lambda x, y: bool(x or y), iterable)
    max(iterable[, args...][, key]) == reduce(lambda x, y: x if key(x) > key(y) else y, iterable_and_args)
    min(iterable[, args...][, key]) == reduce(lambda x, y: x if key(x) < key(y) else y, iterable_and_args)
    sum(iterable[, start]) == reduce(lambda x, y: x + y, iterable, start)
  • map(function, iterable, ...) 
    这个函数的主要功能与我们定义的map_相同。需要补充一点: 
    map还可以接受多个iterable作为参数,在第n次调用function时,将使用iterable1[n], iterable2[n], ...作为参数。
  • filter(function, iterable) 
    这个函数的功能是过滤出iterable中所有以元素自身作为参数调用function时返回True或bool(返回值)为True的元素并以列表返回,与系列第一篇中的my_filter函数相同。
  • zip(iterable1, iterable2, ...) 
    这个函数返回一个列表,每个元素都是一个元组,包含(iterable1[n], iterable2[n], ...)。 
    例如:zip([1, 2], [3, 4]) --> [(1, 3), (2, 4)] 
    如果参数的长度不一致,将在最短的序列结束时结束;如果不提供参数,将返回空列表。

除此之外,你还可以使用本文2.5节中提到的functools.partial()为这些内置函数创建常用的偏函数。

另外,pypi上有一个名为functional的模块,除了这些内建函数外,还额外提供了更多的有意思的函数。但由于使用的场合并不多,并且需要额外安装,在本文中就不介绍了。但我仍然推荐大家下载这个模块的纯Python实现的源代码看看,开阔思维嘛。里面的函数都非常短,源文件总共只有300行不到,地址在这里:http://pypi.python.org/pypi/functional

此篇结束:)


Python函数式编程 网上找到了Python函数式编程的优秀博文一篇,为了避免遗失及熟悉xelatex排版,所以全文整理,我只负责整理,版权归作者所有。 立即下载

相关推荐

十分钟入门Python函数式编程

该文档是国外的Brandon Skerritt写的python函数式编程教科书,十分钟完全可以学会,一起加油!

创建新函数

创建新函数 def(即define,定义):创建新函数,也就是定义一个新函数。 arg(即argument):参数。 return:即返回结果。 例子: 这是梯形计算公式S = 1/2 * (a + b) * h def Trapezoidal_formula(a, b, h): Trapezoidal = 1/2 * (a + b) * h return str(Trapezoidal) + ‘cm’ C2F = Trapezoidal_formula(6, 10, 8) print(C2F) 运行后就

jin5628970的博客 753

Python函数式编程(第2版)1

前言512345810139671211此图标表示警告或需要特别注意的内容。此图标表示提示或技巧。问题与反馈一

chatgpt赋能python:用Python计算三角函数的方法总结

本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc大模型,只是展现它原本的实力。对于颠覆工作方式的ChatGPT,应该选择拥抱而不是抗拒,未来属于“会用”AI的人。🧡AI职场汇报智能办公文案写作效率提升教程 🧡专注于AI+职场+办公方向。下图是课程的整体大纲下图是AI职场汇报智能办公文案写作效率提升教程中用到的ai工具。

lvsetongdao123的博客 4605

模拟IC版图DRC实战:手把手教你搞定MIM电容天线错误和ESD.10g违例

本文深入解析模拟IC版图中的MIM电容天线错误和ESD.10g违例问题,提供从错误解码到实战修复的完整指南。通过电路图修改、版图优化和验证闭环等步骤,帮助工程师高效解决DRC错误,特别适用于ADC等精密模拟电路设计。文章还分享了高级排错技巧和预防性设计策略,大幅提升流片成功率。

weixin_27697385的博客 295

LCD工程师必看:MIPI DSI的LP/HS模式切换全流程拆解(附高通平台实测)

本文为LCD工程师深度解析MIPI DSI接口中低速(LP)与高速(HS)模式切换的全流程。文章结合高通平台实测波形,从协议状态机、时序关键参数到实战调试案例,系统拆解了模式切换的本质、协同机制及常见问题排查方法,重点阐述了LP模式在低功耗控制与HS模式在高速数据传输中的核心作用与切换时序。

weixin_29240711的博客 547

python中三角函数计算

1、采用math库计算 #!/usr/bin/python import math print "cos(3) : ", math.cos(3) print "cos(-3) : ", math.cos(-3) print "cos(0) : ", math.cos(0) print "cos(math.pi) : ", math.cos(math.pi) print "cos(2*math.pi) : ", math.cos(2*math.pi) 计算结果 cos(3) : -0.98999

fbkfbk1的博客 1万+

基于ESP32与PCM5102的WiFi无损音频传输系统设计与实现

本文详细介绍基于ESP32与PCM5102的WiFi无损音频传输系统设计与实现。通过I2S接口直接传输PCM数据,避免SRC重采样,实现真正的HIFI级音质。涵盖硬件连接、软件架构、网络传输优化及实际音质对比,为音频爱好者提供高性价比的无损无线音频解决方案。

rnn9storyteller的博客 948

python函数式编程 第2版 pdf_Python函数式编程 第2版

前言第 1章 函数式编程概述 11.1 编程范式 11.2 细分过程范式 21.2.1 使用函数式范式 31.2.2 使用混合范式 51.2.3 对象的创建过程 61.2.4 乌龟塔 71.3 函数式编程经典示例 71.4 EDA 101.5 小结 10第 2章 函数式编程的特点 112.1 头等函数 112.1.1 纯函数 122.1.2 高阶函数 132.2 不可变数据结构 132.3 严格求...

weixin_35691102的博客 1242

人工智能入门系列之一: 鸢尾花(Iris)多分类的神经网络详解及代码实现

这是最好的时代,我们一起来打造属于自动驾驶汽车上路、无人机飞天、智能机器人管工厂的AI未来 人工智能领域分化为两个阵营:其一是规则式(rule-based)方法,在人工智能早期占主峰;其二是神经网络(neural network)方法,后起之秀。随着硬件水平的提高,算力的指数式增长;人工智能的重心已经从规则式的专家时代转移到神经网络的数据时代。 “神经网络”不选择把人脑熟稔的逻辑规则传授给计算机...

NLP家的码奴小荷的博客 2万+

告别OLE!Delphi操作Excel的3种轻量级方案横向评测(FlexCel/XLSReadWriteII/LibXL)

本文深入评测了Delphi操作Excel的三种轻量级方案:FlexCel、XLSReadWriteII和LibXL。通过技术架构、API设计、性能测试和实战案例的全面对比,帮助开发者选择最适合的工具,提升Excel文件处理效率,告别传统OLE方案的依赖和性能问题。

onion的博客 929

python函数式编程 pdf-Python函数式编程指南(二):从函数开始

2. 从函数开始2.1. 定义一个函数如下定义了一个求和函数:def add(x, y):return x + y关于参数和返回值的语法细节可以参考其他文档,这里就略过了。使用lambda可以定义简单的单行匿名函数。lambda的语法是:lambda args: expression参数(args)的语法与普通函数一样,同时表达式(expression)的值就是匿名函数调用的返回值;而lambda...

weixin_39782573的博客 159

SRAM ECC原理与应用:从汉明码到高可靠嵌入式系统设计

在嵌入式系统与高可靠性计算领域,内存数据完整性是系统稳定运行的基石。软错误(Soft Error)由宇宙射线或芯片内部粒子引发,可能导致存储单元发生位翻转,进而引发程序跑飞或数据损坏。为应对这一物理层挑战,错误校验与纠正(ECC)技术应运而生,其核心原理基于扩展汉明码,通过增加校验位实现单错误纠正、双错误检测(SECDED)能力。这项技术通过硬件透明纠错,在提升系统可靠性的同时,几乎不影响访问性能。在汽车电子、工业控制及航空航天等对安全性要求极高的场景中,ECC已成为保障长期稳定运行的关键硬件机制。本文聚焦

weixin_28728265的博客 529

Python函数式编程指南(二):从函数开始

2. 从函数开始 2.1. 定义一个函数 如下定义了一个求和函数:   复制代码代码如下:   def add(x, y):     return x + y     关于参数和返回值的语法细节可以参考其他文档,这里就略过了。 使用lambda可以定义简单的单行匿名函数。lambda的语法是:   复制代码代码如下:   lambda args: expression

nibudong1902的博客 286

dolphinscheduler-3.4.0

dolphinscheduler集群部署

docsz的博客 660

基于若依的ruoyi-nbcio-plus支持VForm3表单字段数据保存到数据库的一种方法——全网首创(三)

基于若依的ruoyi-nbcio-plus支持VForm3表单字段数据保存到数据库的一种方法——全网首创(三)

宁波阿成的博客 524
上一篇: Python函数式编程指南(一):概述
下一篇: Python函数式编程指南(三):迭代器
Scandinavians
博客等级 码龄19年 36粉丝 121原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值