首页 > 编程语言 >花式涵数编程

花式涵数编程

时间:2023-08-03 17:04:08浏览次数:42  
标签:return 函数 sum 编程 涵数 花式 func msg def


       

1 美人心计

今日向大家介绍后花园中的3位美人,分别是命令氏、面向对象氏、函数氏。

  • 命令氏,妃,贤妻良母,夫唱妇随,和她在一起四字可形容,简单粗暴;
  • 面向对象氏,嫔,聪明伶俐,足智多谋,心眼一个接着一个,省了我不少事情;
  • 函数氏,贵人,零零后,八面玲珑,火星语乱飞,女孩的心思你别猜。

她们国色天香,楚楚动人,大概是下面这个样子:

2 求和问题

我曾遇到“求和问题”,美人傍身各施其计。问题如下:

  1. 求x和y的和(测试用例:x=1,y=2)
  2. 求x和y的平方的和(测试用例:x=1,y=2)
  3. 求x的m次方和y的n次方的和(测试用例:x=1,y=2,m=3,n=4)

2.1 命令氏

命令氏的方法简单粗暴,可行且有效,但是有些笨拙。定义3个函数sum1sum2sum3,依次解决上面的3个问题。


 

def          sum1         (         x         ,         y         )         :


             return         x         +         y


                  


def          sum2         (         x         ,         y         )         :


             return         x*         *         2         +         y*         *         2


                  


def          sum3         (         x         ,         y         ,         m         ,         n         )         :


             return         x*         *         m         +         y*         *         n


                  


sum1         (         1         ,         2         )         # 3


sum2         (         1         ,         2         )         # 5


sum3         (         1         ,         2         ,         3         ,         4         )         # 17



 




 

2.2 面向对象氏

面向对象氏的方法要美得多,两个字“优雅”。所以,面向对象氏一直是枕边佳人,恩宠备至。封装、继承、多态是面向对象氏的特色,对于sum函数,传入不同的参数将会触发不同的计算过程。放到C++里描述,sum可以写成2个函数,int Sum::sum(void)int Sum::sum(int, int)


 

class         Sum         :


                  


             def          __int__         (         self         ,         x         ,         y         )         :


                 self         .         x         ,         self         .         y         =         x         ,         y


                  


             def          sum         (         self         ,         m         =         1         ,         n         =         1         )         :


                 return         self         .         x*         *         m         +         self         .         y*         *         n


                  


s         =         Sum         (         1         ,         2         )


s         .         sum         (         )         # 3


s         .         sum         (         2         ,         2         )         # 5


s         .         sum         (         3         ,         4         )         # 17


 




 

2.3 函数氏

函数氏的方法要奇特的多,乍一看有点笨,但却是完全不一样的思想。


def          sum         (         x         ,         y         ,         f         ,         g         )         :


             return         f         (         x         )         +         g         (         y         )


                  


def          f1         (         x         )         :


             return         x


                  


def          f2         (         x         )         :


             return         x*         *         2


                  


def          f3         (         x         )         :


             return         x*         *         3


                  


def          f4         (         x         )         :


             return         x*         *         4


                  


sum         (         1         ,         2         ,         f1         ,         f1         )         # 3


sum         (         1         ,         2         ,         f2         ,         f2         )         # 5


sum         (         1         ,         2         ,         f3         ,         f4         )         # 17

 



解决了今日的“求和问题”,可能会遇到明天的“求差问题”,问题无穷匮也。而我们心中的困惑在于,如何确定编码的粒度,就像做一款产品,哪些功能该加,哪些功能不该加,哪些功能暂时不加,如果某一个功能以后要加,能不能很好的融入到已有的产品中。

3 翻牌函数氏

函数氏的功劳在于抽象出了sum的求解公式:$sum(x,y)=f(x)+g(y)$,非常有数学风啊哈。但是,方案还是有瑕疵。4个函数$f_1,f_2,f_3,f_4$分别用于计算$x_k,k \in \{1,2,3,4\}$。当我们需要计算$x_{k’},k’ \in [1,100]$怎么办?劳心者治人,我们可以做得更漂亮,比如这样。


 

def          sum         (         x         ,         y         ,         f         ,         g         )         :


             return         f         (         x         )         +         g         (         y         )


                  


def          generate_func         (         k         )         :


             def          func         (         x         )         :


                 return         x*         *         k


             return         func


                  


sum         (         1         ,         2         ,         generate_func         (         1         )         ,         generate_func         (         1         )         )         # 3


sum         (         1         ,         2         ,         generate_func         (         2         )         ,         generate_func         (         2         )         )         # 5


sum         (         1         ,         2         ,         generate_func         (         3         )         ,         generate_func         (         4         )         )         # 17




如果又有一个新的问题,求x的1/m的n次方和y的和(测试用例:x=6,y=6,m=3,n=4),函数氏解决起来会更加酸爽。

def          sum         (         x         ,         y         ,         f         ,         g         )         :


             return         f         (         x         )         +         g         (         y         )


                  


def          generate_func2         (         m         ,         n         )         :


             def          func         (         x         )         :


                 return         (         x         /         m         )         *         *         n


             return         func


                  


sum         (         6         ,         6         ,         generate_func2         (         3         ,         4         )         ,         generate_func         (         1         )         )         # 22

 




可以看到,函数氏最大的魅力在于,函数和数据都可以作为输入,优势很明显,除了喂给你数据,还可以控制你如何吃数据,一切尽在掌握。

3.1 高阶函数(Higher-order Function)

generate_func着实帮了大忙,他可以动态生成函数,而无需人工蛮力定义。除了省时省力,最大的好处是生成的函数有无限个,这是人工所不能及的。高阶函数就是generate_func这样的函数,要么输入中至少有一个函数,要么输出一个函数,至少满足两个条件中的一个。何谓高阶?高低是需要比较的,人比小兔子要高阶,大学数学比初中数学要高阶,我心里的她要比其他人高阶,这就是高阶。高阶函数比普通意义的函数高阶。

为什么高阶函数更牛逼?有一个词叫“泛化”,是从具体到抽象,抽象可以让我们站在更高的位置看待这芸芸众生,然后悟出什么人生道理。什么模块化、面向对象、设计模式blabla,我们不都是在追求抽象,追求“泛”吗?从一个函数生成无数个函数,这不就是四两拨千斤,一生二二生三嘛!

所以高阶函数实至名归。既然高阶函数这么“泛”,为啥不叫“泛函数”?

高阶函数在数学中也叫做算子(运算符)或泛函。

3.2 闭包(Closure)

当我们使用高阶函数来生成函数的时候,可以使用以下两种方法。方法一是将要生成的函数f写在高阶函数gen_f内部;方法二是将f写在外部。通常我们使用第一种,这就和定义局部变量差不多,在哪用就在哪定义,肥水不流外人田,减少对外界的污染。

# method 1


def          gen_f         (         )         :


             def         f         (         )         :


                 pass


             return         f


                  


# method 2


def         f         (         )         :


             pass


def          gen_f         (         )         :


             return         f




一旦我们承认并习惯使用第一种方法的时候,就可能会写出以下风格的代码。

def          gen_f         (         )         :


             array         =         [         ]


             def         f         (         )         :


                 array         .         append         (         1         )


                 return         array


                return         f


                  


func         =         gen_f         (         )


func         (         )         # [1]


func         (         )         # [1, 1]


func         (         )         # [1, 1, 1]

 



预料之外,情理之中,f就是闭包函数。func作为生成出来的函数,每次调用时都会往array里放一个数字1,而array是在外部的gen_f中定义的。这时就需要作出选择,是修改外部的array还是抛出一个找不到array的错误。支持闭包特性的编程语言选择的是前者。

闭包函数和其引用的变量将一同存在,所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

3.3 柯里化(Currying)

如果我们习惯了生成函数带来的快感,也很有可能写出以下代码。方法一和方法二都实现了同样的功能,不同之处在于方法一每次只传一个参数,而方法二一次性把所有参数传入进去。

# method 1


def         f         (         x         )         :


             def         g         (         y         )         :


                 def         h         (         z         )         :


                     return         x         +         y         +         z


                 return         h


             return         g


f         (         1         )         (         2         )         (         3         )         # 6


                  


# method 2


def         f         (         x         ,         y         ,         z         )         :


             return         x         +         y         +         z


f         (         1         ,         2         ,         3         )         # 6




尽管方法一看起来有点啰嗦,但这也意味函数氏在我们心中的地位大大提升。有点“后宫佳丽三千,却偏偏宠她一人”的感觉啊哈。

从方法二到方法一的变换称为柯里化,即把接受多个参数的函数变成每次只接受一个参数的函数,并返回接受余下的参数的函数。有点拗口,就是通过多次调用函数来代替一次传入多个参数。

柯里化的优势在于可以将抽象的函数具体化,比如打印日志。



 

def          print_msg         (         label         ,         msg         )         :


             print         '[%s] %s'         %         (         label         ,         msg         )


                  


# no currying    


print_msg         (         'error'         ,         'network failed'         )


print_msg         (         'info'         ,         'init ok'         )


                  


# use currying


print_err_msg         =         curry         (         print_msg         )         (         'error'         )


print_info_msg         =         curry         (         print_msg         )         (         'info'         )


                  


print_err_msg         (         'network failed'         )


print_info_msg         (         'init ok'         )



其中,函数curry表示将输入的函数柯里化。

3.4 偏函数(Partial Function)

坏消息是Python并没有提供curry函数,好消息是有一些第三方的可以实现该效果,比如https://github.com/kachayev/fn.py,这个库可以给Python插上函数式编程的翅膀。Python的内置functools模块提供了类似curry的功能,名曰偏函数。


 


from          functools          import          partial


                  


def          print_msg         (         label         ,         msg         )         :


             print         '[%s] %s'         %         (         label         ,         msg         )


                  


# use partial


print_err_msg         =         partial         (         print_msg         ,         'error'         )


print_info_msg         =         partial         (         print_msg         ,         'info'         )


                  


print_err_msg         (         'network failed'         )


print_info_msg         (         'init ok'         )

 




柯里化和偏函数类似但不同,柯里化是将多参数函数转变为一系列单参数函数的链式调用,而偏函数是事先固定好一部分参数后面就无需重复传入了。两者都可以实现函数的具体化,固定函数的一部分参数来达到特定的应用。

3.5 匿名函数

使用函数原来可以如此之爽,恩,函数有意思。但是函数的定义着实是个麻烦,我们曾经写过以下代码。


def          sum         (         x         ,         y         ,         f         ,         g         )         :


             return         f         (         x         )         +         g         (         y         )


                  


def          f1         (         x         )         :


             return         x


                  


def          f2         (         x         )         :


             return         x*         *         2


                  


def          f3         (         x         )         :


             return         x*         *         3


                  


def          f4         (         x         )         :


             return         x*         *         4


                  


sum         (         1         ,         2         ,         f1         ,         f1         )         # 3


sum         (         1         ,         2         ,         f2         ,         f2         )         # 5


sum         (         1         ,         2         ,         f3         ,         f4         )         # 17


 




烦。此时,匿名函数的威力便可发挥出来了,如下。lambda可以使我们达到快速定义并使用函数的效果,绿色无污染,干净利索,棒!

def          sum         (         x         ,         y         ,         f         ,         g         )         :


             return         f         (         x         )         +         g         (         y         )


                  


sum         (         1         ,         2         ,         lambda         x         :         x         ,         lambda         x         :         x         )         # 3


sum         (         1         ,         2         ,         lambda         x         :         x*         *         2         ,         lambda         x         :         x*         *         2         )         # 5


sum         (         1         ,         2         ,         lambda         x         :         x*         *         3         ,         lambda         x         :         x*         *         4         )         # 17


 



 




 

3.6 map、reduce、filter

map、reduce、filter是Python内置的高阶函数,通过传入函数可以实现某些特定的功能,通过使用这些函数可以让代码更加简洁,逼格更上一层楼。


array         =         [         1         ,         2         ,         3         ]


                  


### [1,2,3]变换为[1*1,2*2,3*3]


# bad


result         =         [         ]


for         i         in         array         :


             result         .         append         (         i*         i         )


                  


# good


map         (         lambda         x         :         x*         x         ,         array         )         # [1,4,9]


                  


                  


### 求[1,2,3]中元素的和


# bad


result         =         0


for         i         in         array         :


             result         +=         i


                  


# good


reduce         (         lambda         x         ,         y         :         x         +         y         ,         array         )         # 6


                  


                  


### 求[1,2,3]中的奇数


# bad


result         =         [         ]


for         i         in         array         :


             if         i         %         2         :


                 result         .         append         (         i         )           


                  


# good


filter         (         lambda         x         :         x         %         2         ,         array         )         # [1,3]

 



 




 

参考

标签:return,函数,sum,编程,涵数,花式,func,msg,def
From: https://blog.51cto.com/u_6186189/6950875

相关文章

  • 【测试】SAS 编程技巧 - PROC SQL(二)
    上一节中,我们介绍了如何使用SQL创建、删除数据集、修改数据集结构,以及如何新增、删除和更新数据集的观测,所涉及到的内容都是对数据集的增、删、改的操作,从本节开始,我们将对SQL中最常见,也最灵活的查询操作进行详细的介绍。查询语句SQL的查询操作是通过SELECT语句实现的。S......
  • 【测试】SAS 编程技巧 - PROC SQL(一)
    SQL全称StrucuredQueryLanguage,即结构化查询语言,广泛应用于关系型数据库中。SASBase使用PROCSQL提供了对SQL的实现。PROCSQL过程可以帮助我们完成以下任务:创建数据集、视图和索引删除数据集、视图和索引修改数据集的结构更新数据集的观测从数据集或视图中获取......
  • 深入浅出RxJava (四:在Android中使用响应式编程)
    [url=http://blog.danlew.net/2014/10/08/grokking-rxjava-part-4/]原文链接[/url]在第1,2,3篇中,我大概介绍了RxJava是怎么使用的。下面我会介绍如何在Android中使用RxJava.RxAndroidRxAndroid是RxJava的一个针对Android平台的扩展。它包含了一些能够简化And......
  • SAS 编程技巧 - PROC SQL(四)
    上一节,我们介绍了使用SELECT语句对变量进行查询,这一节我们继续介绍SELECT的简单查询操作。常量常量包括数值常量和字符串常量,有时候也被称为字面量(literal)。procsqlnoprint;createtableADSLasselect"TEST-CLINICAL-TRIAL-2023-0012"asST......
  • 面向对象编程基础
    欢迎来到C#语言入门指南的第二篇博客!在前一篇博客中,我们了解了C#语言的基本概念和历史,并成功编写了您的第一个C#程序。今天,我们将深入探讨面向对象编程(Object-OrientedProgramming,OOP)的基础知识。OOP是一种常用的编程范式,它将数据和操作数据的方法组织成对象,以便更好地模拟现实世......
  • Java编程-依据类图与流程图实现对应接口
    类图依据与流程图依据封装常见的HTTP状态码RegisterController接口register(Stringname,Stringpwd)login(Stringname,Stringpwd)NovelController接口addNovel()asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfNovelContentController接口asdfasdfasdfasdfasdf......
  • 【雕爷学编程】Arduino动手做(180)---Seeeduino Lotus开发板
    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来—小小的进步或是搞......
  • 可编程的流式计算框架:YoMo
    音视频领域的新技术应用非常多,但是在工业和IoT领域,新技术的应用却鲜有耳闻。本次LiveVideoStackCon2021上海站大会我们邀请到了熹乐科技YoMo框架负责人——洪小坚,为我们分享熹乐科技和YoMo会为工业和IoT带来哪些新鲜血液。文/洪小坚整理/LiveVideoStack大家好,今天分享的主题......
  • 编程学习一些思路
    亲历分享:自学编程的致命误区,你中招了没?在职程序员聊聊自学时如何防止入坑-YouTube不顾基础,盲目追求时髦技术,基础概念和基础路线很重要!理清基础概念,选好基础路线。打好基础。必须学习最好的语言语言不分好坏,看你的场景和目标、用途孤军奋战,不去交流敢于分享,走出去......
  • ROS参数使用与编程方法
    参数参数概念在ROSMaster中,存在一个参数服务器(ParameterServer),它是一个全局字典,即一个全局变量的存储空间,用来保存各个节点的配置参数。各个节点都可以对参数进行全局访问。创建功能包cd~/catkin_ws/srccatkin_create_pkglearning_parameterroscpprospystd_srvs参数......