跟老齐学Python之大话题小函数(1)_python

开篇就要提到一个大的话题:编程范型。什么是编程范型?引用维基百科中的解释:

复制代码 代码如下:

编程范型或编程范式(英语:Programming paradigm),(范即模范之意,范式即模式、方法),是一类典型的编程风格,是指从事软件工程的一类典型的风格(可以对照方法学)。如:函数式编程、程序编程、面向对象编程、指令式编程等等为不同的编程范型。

编程范型提供了(同时决定了)程序员对程序执行的看法。例如,在面向对象编程中,程序员认为程序是一系列相互作用的对象,而在函数式编程中一个程序会被看作是一个无状态的函数计算的串行。
 
正如软件工程中不同的群体会提倡不同的“方法学”一样,不同的编程语言也会提倡不同的“编程范型”。一些语言是专门为某个特定的范型设计的(如Smalltalk和Java支持面向对象编程,而Haskell和Scheme则支持函数式编程),同时还有另一些语言支持多种范型(如Ruby、Common Lisp、Python和Oz)。
 
编程范型和编程语言之间的关系可能十分复杂,由于一个编程语言可以支持多种范型。例如,C++设计时,支持过程化编程、面向对象编程以及泛型编程。然而,设计师和程序员们要考虑如何使用这些范型元素来构建一个程序。一个人可以用C++写出一个完全过程化的程序,另一个人也可以用C++写出一个纯粹的面向对象程序,甚至还有人可以写出杂揉了两种范型的程序。

不管看官是初学者还是老油条,都建议将上面这段话认真读完,不管理解还是不理解,总能有点感觉的。

这里推荐一篇文章,这篇文章来自网络:《主要的编程范型》

扯了不少编程范型,今天本讲要讲什么呢?今天要介绍几个python中的小函数,这几个函数都是从函数式编程借鉴过来的,它们就是:

filter、map、reduce、lambda、yield

有了它们,最大的好处是程序更简洁;没有它们,程序也可以用别的方式实现,只不过麻烦一些罢了。所以,还是能用则用之吧。

lambda

lambda函数,是一个只用一行就能解决问题的函数,听着是多么诱人呀。看下面的例子:

复制代码 代码如下:

>>> def add(x):     #定义一个函数,将输入的变量增加3,然后返回增加之后的值
...     x +=3
...     return x
...
>>> numbers = range(10)
>>> numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  #有这样一个list,想让每个数字增加3,然后输出到一个新的list中

>>> new_numbers = []
>>> for i in numbers:
...     new_numbers.append(add(i))  #调用add()函数,并append到list中
...
>>> new_numbers
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

 在这个例子中,add()只是一个中间操作。当然,上面的例子完全可以用别的方式实现。比如:

复制代码 代码如下:

>>> new_numbers = [ i+3 for i in numbers ]
>>> new_numbers
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

 首先说明,这种列表解析的方式是非常非常好的。

但是,我们偏偏要用lambda这个函数替代add(x),如果看官和我一样这么偏执,就可以:

复制代码 代码如下:

>>> lam = lambda x:x+3
>>> n2 = []
>>> for i in numbers:
...     n2.append(lam(i))
...
>>> n2
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

 这里的lam就相当于add(x),请看官对应一下,这一行lambda x:x+3就完成add(x)的三行(还是两行?),特别是最后返回值。还可以写这样的例子:

复制代码 代码如下:

>>> g = lambda x,y:x+y  #x+y,并返回结果
>>> g(3,4)
7
>>> (lambda x:x**2)(4)  #返回4的平方
16

 通过上面例子,总结一下lambda函数的使用方法:
 •在lambda后面直接跟变量
 •变量后面是冒号
 •冒号后面是表达式,表达式计算结果就是本函数的返回值
 
为了简明扼要,用一个式子表示是必要的:

复制代码 代码如下:

lambda arg1, arg2, ...argN : expression using arguments

 要特别提醒看官:虽然lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值,但是lambda 函数不能包含命令,包含的表达式不能超过一个。不要试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。

就lambda而言,它并没有给程序带来性能上的提升,它带来的是代码的简洁。比如,要打印一个list,里面依次是某个数字的1次方,二次方,三次方,四次方。用lambda可以这样做:

复制代码 代码如下:

>>> lamb = [ lambda x:x,lambda x:x**2,lambda x:x**3,lambda x:x**4 ]
>>> for i in lamb:
...     print i(3),
...
3 9 27 81

 lambda做为一个单行的函数,在编程实践中,可以选择使用。根据我的经验,尽量少用,因为它或许更多地是为减少单行函数的定义而存在的。

map

先看一个例子,还是上面讲述lambda的时候第一个例子,用map也能够实现:

复制代码 代码如下:

>>> numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]      #把列表中每一项都加3

>>> map(add,numbers)                #add(x)是上面讲述的那个函数,但是这里只引用函数名称即可
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

>>> map(lambda x: x+3,numbers)      #用lambda当然可以啦
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

 map()是python的一个内置函数,它的基本样式是:map(func, seq),func是一个函数,seq是一个序列对象。在执行的时候,序列对象中的每个元素,按照从左到右的顺序,依次被取出来,并塞入到func那个函数里面,并将func的返回值依次存到一个list中。

在应用中,map的所能实现的,也可以用别的方式实现。比如:

复制代码 代码如下:

>>> items = [1,2,3,4,5]
>>> squared = []
>>> for i in items:
...     squared.append(i**2)
...
>>> squared
[1, 4, 9, 16, 25]

>>> def sqr(x): return x**2
...
>>> map(sqr,items)
[1, 4, 9, 16, 25]

>>> map(lambda x: x**2,items)
[1, 4, 9, 16, 25]

>>> [ x**2 for x in items ]     #这个我最喜欢了,一般情况下速度足够快,而且可读性强
[1, 4, 9, 16, 25]

 条条大路通罗马,以上方法,在编程中,自己根据需要来选用啦。

在以上感性认识的基础上,在来浏览有关map()的官方说明,能够更明白一些。

复制代码 代码如下:

map(function, iterable, ...)

Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. If one iterable is shorter than another it is assumed to be extended with None items. If function is None, the identity function is assumed; if there are multiple arguments, map() returns a list consisting of tuples containing the corresponding items from all iterables (a kind of transpose operation). The iterable arguments may be a sequence or any iterable object; the result is always a list.

理解要点:
 •对iterable中的每个元素,依次应用function的方法(函数)(这本质上就是一个for循环)。
 •将所有结果返回一个list。
 •如果参数很多,则对么个参数并行执行function。
 
例如:

复制代码 代码如下:

>>> lst1 = [1,2,3,4,5]
>>> lst2 = [6,7,8,9,0]
>>> map(lambda x,y: x+y, lst1,lst2)     #将两个列表中的对应项加起来,并返回一个结果列表
[7, 9, 11, 13, 5]

 请看官注意了,上面这个例子如果用for循环来写,还不是很难,如果扩展一下,下面的例子用for来改写,就要小心了:

复制代码 代码如下:

>>> lst1 = [1,2,3,4,5]
>>> lst2 = [6,7,8,9,0]
>>> lst3 = [7,8,9,2,1]
>>> map(lambda x,y,z: x+y+z, lst1,lst2,lst3)
[14, 17, 20, 15, 6]

 这才显示出map的简洁优雅。

预告:下一讲详解reduce和filter

时间: 2024-12-29 21:16:15

跟老齐学Python之大话题小函数(1)_python的相关文章

跟老齐学Python之大话题小函数(2)_python

上一讲和本讲的标题是"大话题小函数",所谓大话题,就是这些函数如果溯源,都会找到听起来更高大上的东西.这种思维方式绝对我坚定地继承了中华民族的优良传统的.自从天朝的臣民看到英国人开始踢足球,一直到现在所谓某国勃起了,都一直在试图论证足球起源于该朝的前前前朝的某国时代,并且还搬出了那时候的一个叫做高俅的球星来论证,当然了,勃起的某国是挡不住该国家队在世界杯征程上的阳痿,只能用高俅来意淫一番了.这种思维方式,我是坚定地继承,因为在我成长过程中,它一直被奉为优良传统.阿Q本来是姓赵的,和赵老

跟老齐学Python之从if开始语句的征程_python

一般编程的教材,都是要把所有的变量类型讲完,然后才讲语句.这种讲法,其实不符合学习的特点.学习,就是要循序渐进的.在这点上,我可以很吹一通了,因为我做过教师,研究教育教学,算是有一点心得的.所以,我在这里就开始讲授语句. 什么是语句 在前面,我们已经写了一些.py的文件,这些文件可以用python来运行.那些文件,就是由语句组成的程序. 为了能够严谨地阐述这个概念,我还是要抄一段维基百科中的词条:命令式编程 命令式编程(英语:Imperative programming),是一种描述电脑所需作出

跟老齐学Python之深入变量和引用对象_python

在<永远强大的函数>那一讲中,老齐我已经向看官们简述了一下变量,之后我们就一直在使用变量,每次使用变量,都要有一个操作,就是赋值.本讲再次提及这个两个事情,就是要让看官对变量和赋值有一个知其然和知其所以然的认识.当然,最后能不能达到此目的,主要看我是不是说的通俗易懂了.如果您没有明白,就说明我说的还不够好,可以联系我,我再为您效劳. 变量和对象 在<learning python>那本书里面,作者对变量.对象和引用的关系阐述的非常明了.我这里在很大程度上是受他的启发.感谢作者Mar

跟老齐学Python之做一个小游戏_python

在讲述有关list的时候,提到做游戏的事情,后来这个事情一直没有接续.不是忘记了,是在想在哪个阶段做最合适.经过一段时间学习,看官已经不是纯粹小白了,已经属于python初级者了.现在就是开始做那个游戏的时候了. 游戏内容:猜数字游戏 太简单了吧.是的,游戏难度不大,不过这个游戏中蕴含的东西可是值得玩味的. 游戏过程描述 程序运行起来,随机在某个范围内选择一个整数. 提示用户输入数字,也就是猜程序随即选的那个数字. 程序将用户输入的数字与自己选定的对比,一样则用户完成游戏,否则继续猜. 使用次数

跟老齐学Python之赋值,简单也不简单_python

变量命名 在<初识永远强大的函数>一文中,有一节专门讨论"取名字的学问",就是有关变量名称的问题,本温故而知新的原则,这里要复习: 名称格式:(下划线或者字母)+(任意数目的字母,数字或下划线) 注意:  1.区分大小写  2.禁止使用保留字  3.遵守通常习惯  •以单一下划线开头的变量名(_X)不会被from module import *语句导入的.  •前后有下划线的变量名(X)是系统定义的变量名,对解释器有特殊意义.  •以两个下划线开头,但结尾没有两个下划线的变

跟老齐学Python之编写类之一创建实例_python

说明:关于类的这部分,我参考了<Learning Python>一书的讲解. 创建类 创建类的方法比较简单,如下: 复制代码 代码如下: class Person:  注意,类的名称一般用大写字母开头,这是惯例.当然,如果故意不遵循此惯例,也未尝不可,但是,会给别人阅读乃至于自己以后阅读带来麻烦.既然大家都是靠右走的,你就别非要在路中间睡觉了. 接下来,一般都要编写构造函数,在写这个函数之前,先解释一下什么是构造函数. 复制代码 代码如下: class Person:     def __in

跟老齐学Python之关于类的初步认识_python

在开始部分,请看官非常非常耐心地阅读下面几个枯燥的术语解释,本来这不符合本教程的风格,但是,请看官谅解,因为列位将来一定要阅读枯燥的东西的.这些枯燥的属于解释,均来自维基百科. 1.问题空间 问题空间是问题解决者对一个问题所达到的全部认识状态,它是由问题解决者利用问题所包含的信息和已贮存的信息主动地构成的. 一个问题一般有下面三个方面来定义:  •初始状态--一开始时的不完全的信息或令人不满意的状况:  •目标状态--你希望获得的信息或状态:  •操作--为了从初始状态迈向目标状态,你可能采取的

跟老齐学Python之编写类之二方法_python

数据流转过程 除了在类中可以写这种函数之外,在类中还可以写别的函数,延续上一讲的例子: 复制代码 代码如下: #!/usr/bin/env python #coding:utf-8 class Person:     def __init__(self, name, lang="golang", website="www.google.com"):         self.name = name         self.lang = lang         s

跟老齐学Python之有容乃大的list(3)_python

对list的操作 向list中插入一个元素 前面有一个向list中追加元素的方法,那个追加是且只能是将新元素添加在list的最后一个.如: >>> all_users = ["qiwsir","github"] >>> all_users.append("io") >>> all_users ['qiwsir', 'github', 'io'] 从这个操作,就可以说明list是可以随时改变的.