Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >局部函数实现add(1)(2)(3)

局部函数实现add(1)(2)(3)

作者头像
疯狂软件李刚
发布于 2020-07-07 06:57:05
发布于 2020-07-07 06:57:05
62400
代码可运行
举报
文章被收录于专栏:疯狂软件李刚疯狂软件李刚
运行总次数:0
代码可运行

导读

本文主要介绍如何通过局部函数(高阶函数)来实现函数curry,国内翻译为函数柯里化(这翻译太操蛋了)。这样可通过一个函数同时实现如下调用:

add(1)(2)(3)

add(1, 2)(3)

add(1)(2, 3)

add(1, 2, 3)

一道“难”题

每天都要在各个读者群内看一看,看看各读者有没有遇到难题,一般读者们会互相帮助、解决问题,如果读者们搞不定,我会顺手把问题解决了。

今天看到读者群内有人在问:

这道题的需求在于,同一个函数可以自动处理:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
add(1)(2)(3)  # 6
add(1, 2)(3)  # 6
add(1)(2, 3)  # 6
add(1, 2, 3)  # 6

解决思路

乍一看这题的解决思路就是:让函数返回局部函数。

保证add(1)之后再次返回函数,从而保证add(1)(2)可以调用;

而且还要保证add(1)(2)之后还是返回函数,从而保证add(1)(2)(3)可以调用

如何定义嵌套函数?

如何让函数再次返回函数?

这些都是Python函数式编程的基础内容,详细讲解可参看《疯狂Python讲义》的5.3和5.4两节。

为了引导大家思维,下面先来点简单的,例如将如下接受两个参数函数转成只接受一个参数(curry)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def add (x, y):
    return x + y;
print(add(1, 2))

为了对上面add()函数进行curry,可以考虑定义一个嵌套函数,嵌套函数接受add()函数传入的参数,并添加自己的参数,例如改为如下形式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# curry之后的add函数
def add_curry(x):
    def wa(y):
        return x + y
    return wa
print(add_curry(1)(2))

按照此思路写一个add(1)(2)(3)吧,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def add_curry_curry(x):
    def wa(y):
        def foo (z):
            return x + y + z
        return foo
    return wa
print(add_curry_curry(1)(2)(3))

理一下上面代码定义了几个函数?

add_curry_curry函数包含一个嵌套函数wa,且该函数将wa函数作为返回值。

wa函数包含一个嵌套函数foo,且该函数将foo函数作为返回值。

是不是一切都明朗了?其实并不难,对不对?——说穿了,其实无非就是定义局部函数、返回局部函数。

提示

每当你觉得xxx很难时,往往还是基础不扎实,很多人学编程时难免犯一个方法错误,他把编程知识分成两类:

A:看一眼似乎能学会的。

B:看一眼似乎不能学会的。

对于A类知识,他的反应是:这TM太简单,没必要学习;对于B类知识,他的反应是:这TM太难了,完全超出了我的学习范畴,没法学习。

——所以天底下就没有值得学习的东西。

我的经验是:看似一眼就能学会的知识,你更应该反复练习,找到它们内置的运行机制,以便“温故而知新”;看似学不会的知识,只要多回顾已掌握的知识,就不难发现:“太阳底下没有新知识”——软件领域的创新能力其实非常有限,大部分知识都是模仿、微改变。

最后解决

可能有人会说 ,但我们的要求是一个add函数同时支持下面这几种的用法呢:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
add(1, 2, 3)
add(1, 2)(3)
add(1)(2, 3)

如果你理解了上面两个例子的运行机制(嵌套函数和函数返回值),我们完全可以定义一个工具函数来实现对目标函数的curry。

方法就是,程序只要判断传给函数的参数个数(len(args)与原函数所需参数个数(通过__code__.co_argcount属性获取)的关系即可。

如果传给函数的参数个数大于等于原函数所需的参数个数,则执行函数;否则就返回一个嵌套函数。

我们当然可以自己实现一个工具函数专门来生成 柯里化 函数。

主要思路是什么呢,要判断当前传入函数的参数个数 (args.length) 是否大于等于原函数所需参数个数 (fn.length) ,如果是,则执行当前函数;如果是小于,则返回一个函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 工具函数:用于对目标函数执行curry
def curry (fn, *args):
    # 如果传入参数大于或等于fn函数所需的参数
    if len(args) >= fn.__code__.co_argcount :
        # 直接执行fn函数
        return fn(*args)
    else :
        # 定义局部函数
        def wa (*b):
            # 将args所有函数和*b所有参数作为参数一起传入
            return curry(fn, *args, *b)
        return wa
def test(x, y, z) :
    return x + y + z
# 对test函数执行curry
add = curry(test)
print(add(1)(2)(3))
print(add(1, 2)(3))
print(add(1)(2, 3))
print(add(1, 2, 3))

其实就这么简单,所以我在读者群里顺手把这个问题解决了,把这段代码贴给他们。

为了帮助读者能理解我的解决思路,所以顺手写了本文。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 疯狂软件李刚 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
三行代码实现 add(1)(2)(3)
本文主要从 3W (what, how, why) 角度出发通俗易懂的解释一下 什么是函数柯里化,以及怎么用三行代码来实现 add(1)(2)(3) 这个很常见的面试题。
木子星兮
2020/04/07
8910
Python进阶教程笔记(七)函数式编程
由于参数 x, y 和 f 都可以任意传入,如果 f 传入其他函数,就可以得到不同的返回值。
Lemon黄
2020/10/30
4720
Python进阶教程笔记(七)函数式编程
Python3 函数式编程
高阶函数(Higher-order function),由于在 Python 中,变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接受另一个函数作为参数。接收其他函数作为参数的函数称之为高阶函数。一个简单例子如下:
嵌入式视觉
2022/09/05
3260
Python3 函数式编程
翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 第 3 章:管理函数的输入
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 第 3 章:管理函数的输入(Inputs) 在第 2 章的 “函数输入”
iKcamp
2018/01/04
1.6K0
获取Python函数信息的方法
Python的反射机制可以动态获取对象信息以及动态调用对象,本文介绍如何获取对象中的函数注释信息以及参数信息。
Python学习者
2023/04/14
5320
Python学习笔记(四)·函数式编程
函数是 Python 内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
公爵
2022/09/28
9310
Python学习笔记(四)·函数式编程
从闭包和高阶函数初探JS设计模式
JavaScript是一门完整的面向对象的编程语言,JavaScript在设计之初参考并引入了Lambda表达式、闭包和高阶函数等特性。
小东同学
2022/07/29
5260
从闭包和高阶函数初探JS设计模式
《JavaScript 模式》读书笔记(4)— 函数5
这部分我们主要讨论Curry化和部分函数应用的内容。但是在深入讨论之前,我们需要先了解一下函数应用的含义。
zaking
2020/04/01
5220
《JavaScript ES6 函数式编程入门经典》读书笔记
函数式编程是一种范式,我们能够以此创建仅依赖输入就可以完成自身逻辑的函数。这保证了当函数多次调用时仍然返回相同的结果。函数不会改变任何外部环境的变量,这将产生可缓存,可测试的代码库。
kai666666
2020/10/27
2.3K0
Day7函数式编程3/3
装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。 >>> def now(): ... print('2018-3-27') ... >>> f = now >>> f() 2018-3-27 函数对象有一个__name__属性,可以拿到函数的名字: >>> now.__name__ 'now' >>> f.__name__ 'now' 现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码
林清猫耳
2018/04/26
6510
一文读懂Python 高阶函数
将函数作为参数传入,这样的函数称为高阶函数。函数式编程就是指这种高度抽象的编程范式。 变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。如下所示:
Wu_Candy
2022/07/04
2740
一文读懂Python 高阶函数
函数(function)的前世今生
函数就是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。
江米小枣
2020/06/16
7070
函数(function)的前世今生
Python(七)
Python 内建了 map() 函数。 map() 函数接收两个参数,一个是函数,一个是 Iterable,map 将传入的函数依次作用到序列的每个元素,并把结果作为新的 Iterator 返回。由于结果是一个 Iterator,Iterator 是惰性序列,因此我们还可以通过 list() 函数让它把整个序列都计算出来并返回一个 list。
1ess
2021/11/01
2550
一段柯里化函数代码阅读
柯里化的概念大家应该都清楚,就是将一个接受多个参数的函数转化为接受单一参数的函数的技术。
用户1515472
2019/07/25
3630
python函数高级
函数是指将一组语句的集合通过一个名字(函数名)封装起来,想要执行这个函数,只需要调用函数名即可
程序员皮克
2022/01/04
4840
python中的装饰器decorator
而我们想为这三个函数增加一个函数调用打印功能 类似print("call f1()")
py3study
2020/01/15
5180
Python学习 Day 5 高阶函数 map/reduce filter sorter 返回函数 匿名函数 装饰器 偏函数
>>> abs(-10) #把abs指向10后,无法通过abs(-10)调用该函数
统计学家
2019/04/10
3490
JavaScript 函数式编程中的 curry 实现
最近在学习javascript函数式编程,对其中大名鼎鼎的curry十分感兴趣,curry函数可以接受一个函数,我们暂且称之为原始函数,返回的也是一个函数,柯里化函数,这个返回的柯里化函数功能十分强大,他在执行的过程中,不断的返回一个贮存了传入参数的函数,直到触发了原始函数执行的条件。这么说比较概括,那么就举个例子来说明一下:
哲洛不闹
2018/09/14
5980
JavaScript 函数式编程中的 curry 实现
函数式编程了解一下(上)
所以我们说,函数式编程是一种范式,我们能够以此创建仅依赖输入就可以完成自身逻辑的函数。这保证了当函数多次调用时,依然可以返回相同的结果。因此可以产生可缓存的、可测试的代码库
Nealyang
2019/09/29
5160
函数式编程了解一下(上)
面试官:什么是柯里化?怎样实现柯里化?
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
前端老道
2022/12/01
1.8K0
相关推荐
三行代码实现 add(1)(2)(3)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验