函数和函数式编程

  • 15.1传递函数
  • 15.2 形式参数
    • 15.2.1 位置参数
    • 15.2.2 默认参数
    • 15.2.3 为什么用默认参数?
    • 15.2.4 抓取网页(示例)
  • 15.3 可变长度的参数
    • 15.3.1 非关键字可变长参数(元组/Tuple)
    • 15.3.2 关键字变量参数(字典/Dictionary)

15.1传递函数

函数是可以被引用的(访问或者以其他变量作为其别名),也作为参数传入函数,以及作为列表和字典等等容器对象的元素
函数有一个独一无二的特征使它同其他对象区分开来,那就是函数是可调用的。

举例来说,可以通过函数操作来调用他们。(在 python 中有其他的可调用对象)在以上的描述中,我们注意到可以用其他的变量来做作为函数的别名,因为所有的对象都是通过引用来传递的,函数也不例外。当对一个变量赋值时,实际是将相同对象的引用赋值给这个变量。如果对象是函数的话,这个对象所有的别名都是可调用的。

>>> def foo():
... print 'in foo()'
...
>>> bar = foo
>>> bar()
in foo()

当我们把 foo 赋值给 bar 时,bar 和 foo 引用了同一个函数对象,所以能以和调用 foo()相同的方式来调用 bar()。确定你明白**“foo”(函数对象的引用)和"foo()"(函数对象的调用)**的区别。稍微深入下我们引用的例子,我们甚至可以把函数作为参数传入其他函数来进行调用。

>>> def bar(argfunc):
...     argfunc()
...
>>> bar(foo)
in foo()

注意到函数对象 foo 被传入到 bar()中。bar()调用了 foo()(用局部变量 argfunc 来作为其别名,就如同在前面的例子中我们把 foo 赋给 bar 一样)

 #!/usr/bin/env pythondef convert(func, seq):'conv. sequence of numbers to same type'return [func(eachNum) for eachNum in seq]myseq = (123, 45.67, -6.2e8, 999999999L)print convert(int, myseq)print convert(long, myseq)print convert(float, myseq)

一个将函数作为参数传递,并在函数体内调用这些函数,更加实际的例子。这个脚本用传入的转换函数简单将一个序列的数转化为相同的类型。特别地,convert()函数传入一个内建函数 int(),long()或者 float()来执行转换。
如果我们运行这个程序,我们将会得到如下输出:

$ numconv.py
[123, 45, -620000000, 999999999]
[123L, 45L, -620000000L, 999999999L]
[123.0, 45.67, -620000000.0, 999999999.0]

15.2 形式参数

python 函数的形参集合由在调用时要传入函数的所有参数组成,这参数与函数声明中的参数列表精确的配对。这些参数包括了所有必要参数(以正确的定位顺序来传入函数的),关键字参数(以顺序或者不按顺序传入,但是带有参数列表中曾定义过的关键字),以及所有含有默认值,函数调用时不必要指定的参数。(声明函数时创建的)局部命名空间为各个参数值,创建了一个名字。一旦函数开始执行,即能访问这个名字。

15.2.1 位置参数

这些我们都是熟悉的标准化参数。位置参数必须以在被调用函数中定义的准确顺序来传递。另外,没有任何默认参数(见下一个部分)的话,传入函数(调用)的参数的精确的数目必须和声明的数字一致。

>>> def foo(who): # defined for only 1 argument
... print 'Hello', who
...
>>> foo() # 0 arguments... BAD Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: not enough arguments; expected 1, got 0
>>>
>>> foo('World!') # 1 argument... WORKS Hello World!
>>>
>>> foo('Mr.', 'World!')# 2 arguments... BAD Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: too many arguments; expected 1, got 2

15.2.2 默认参数

对于默认参数如果在函数调用时没有为参数提供值则使用预先定义的的默认值。这些定义在函数声明的标题行中给出。c++也支持默认参数,和 python 有同样的语法:参数名等号默认值。这个从句法上来表明如果没有值传递给那个参数,那么这个参数将取默认值。
python 中用默认值声明变量的语法是所有的位置参数必须出现在任何一个默认参数之前

def func(posargs, defarg1=dval1, defarg2=dval2,...):"function_documentation_string"function_body_suite

每个默认参数都紧跟着一个用默认值的赋值语句。如果在函数调用时没有给出值,那么这个赋值就会实现。

15.2.3 为什么用默认参数?

  1. 默认参数让程序的健壮性上升到极高的级别,因为它们补充了标准位置参数没有提供的一些灵活性。
  2. 使用默认参数的概念与在你的电脑上安装软件的过程类似。一个人会有多少次选择默认安装而不是自定义安装?我可以说可能几乎都是默认安装。这既方便,易于操作,又能节省时间。如果是那些总是选择自定义安装的顽固分子,请记着你只是少数人之一
  3. 另外一个让开发者受益的地方在于,使开发者更好地控制为顾客开发的软件。当提供了默认值的时候,他们可以精心选择“最佳“的默认值,所以用户不需要马上面对繁琐的选项。随着时间流逝,当用户对系统或者 api 越来越熟悉的时候,他们最终能自行给出参数值,便不再需要使用“学
    步车“了

15.2.4 抓取网页(示例)

这段脚本下载了一个 web 页面(默认为本地的 www 服务器)并显示了 html 文件的第一个以及最后一个非空格行。由于 download()函数的双默认参数允许用不同的 urls 或者指定不同的处理函数来进行覆盖,灵活性得倒了提高。

#!/usr/bin/env pythonfrom urllib import urlretrievedef firstNonBlank(lines):for eachLine in lines:if not eachLine.strip():continueelse:return eachLinedef firstLast(webpage):f = open(webpage)lines = f.readlines()f.close()print firstNonBlank(lines),lines.reverse()print firstNonBlank(lines),def download(url='http://www.baidu.com',process=firstLast):try:retval = urlretrieve(url)[0]except IOError:retval = Noneif retval: # do some processingprocess(retval)if __name__ == '__main__':download()
$ grabWeb.py
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
</BODY></HTML>

15.3 可变长度的参数

可能会有需要用函数处理可变数量参数的情况,这时可使用可变长度的参数列表。

变长的参数在函数声明中不是显式命名的,因为参数的数目在运行时之前是未知的(甚至在运行的期间,每次函数调用的参数的数目也可能是不同的),这和常规参数(位置和默认)明显不同,常规参数都是在函数声明中命名的。由于函数调用提供了关键字以及非关键字两种参数类型,python 用两种方法来支持变长参数,
在前几节中,我们了解了在函数调用中使用***符号来指定元组和字典的元素作为非关键字以及关键字参数的方法。在这个部分中,我们将再次使用相同的符号,但是这次在函数的声明中,表示在函数调用时接收这样的参数。这语法允许函数接收在函数声明中定义的形参之外的参数。

15.3.1 非关键字可变长参数(元组/Tuple)

当函数被调用的时候,所有的形参(必须的和默认的)都将值赋给了在函数声明中相对应的局部变量。剩下的非关键字参数按顺序插入到一个元组中便于访问。在函数调用时,接受一个不定(非固定)数目的参数。可变长的参数元组必须在位置和默认参数之后,带元组(或者非关键字可变长参数)的函数普遍的语法如下:

def function_name([formal_args,] *vargs_tuple):"function_documentation_string"function_body_suite

星号操作符之后的形参将作为元组传递给函数,元组保存了所有传递给函数的"额外"的参数(匹配了所有位置和具名参数后剩余的)。如果没有给出额外的参数,元组为空。

正如我们先前看见的,只要在函数调用时给出不正确的函数参数数目,就会产生一个 TypeError异常。通过末尾增加一个可变的参数列表变量,我们就能处理当超出数目的参数被传入函数的情形,因为所有的额外(非关键字)参数会被添加到变量参数元组。(额外的关键字参数需要关键字变量参数.)正如预料的那样,由于和位置参数必须放在关键字参数之前一样的原因,所有的形式参数必须先于非正式的参数之前出现。

#!/usr/bin/python2.7def tupleVarArgs(arg1, arg2='defaultB', *theRest):'display regular args and non-keyword variable args'print 'formal arg 1:',arg1 print 'formal arg 2:',arg2 for eachXtrArg in theRest:print 'another arg:',eachXtrArgtupleVarArgs('abc',123,'xyz',[1,2,3])
[root@localhost day4]# ./tu.py
formal arg 1: abc
formal arg 2: 123
another arg: xyz
another arg: [1, 2, 3]

15.3.2 关键字变量参数(字典/Dictionary)

在我们有不定数目的或者额外集合的关键字的情况中, 参数被放入一个字典中,字典中键为参数名,值为相应的参数值。为什么一定要是字典呢?因为为每个参数-参数的名字和参数值–都是成对给出—用字典来保存这些参数自然就最适合不过了。

这给出使用了变量参数字典来应对额外关键字参数的函数定义的语法:

def function_name([formal_args,][*vargst,] **vargsd):function_documentation_string function_body_suite

为了区分关键字参数和非关键字非正式参数,使用了双星号(**)。 **是被重载了的以便不与幂运算发生混淆。关键字变量参数应该为函数定义的最后一个参数,带**。我们现在展示一个如何使用字典的例子:

def dictVarArgs(arg1, arg2='defaultB', **theRest):'display 2 regular args and keyword variable args'print 'formal arg1:', arg1print 'formal arg2:', arg2for eachXtrArg in theRest.keys():print 'Xtra arg %s: %s' % (eachXtrArg, str(theRest[eachXtrArg]))

在解释器中执行这个代码,我们得到以下输出。

>>> dictVarArgs(1220, 740.0, c='grail')
formal arg1: 1220
formal arg2: 740.0
Xtra arg c: grail
>>>
>>> dictVarArgs(arg2='tales', c=123, d='poe', arg1='mystery')
formal arg1: mystery
formal arg2: tales
Xtra arg c: 123
Xtra arg d: poe
>>>
>>> dictVarArgs('one', d=10, e='zoo', men=('freud', 'gaudi'))
formal arg1: one
formal arg2: defaultB
Xtra arg men: ('freud', 'gaudi')
Xtra arg d: 10
Xtra arg e: zoo

变长参数都有可能用在同一个函数中,只要关键字字典是最后一个参数并且非关键字元组先于它之前出现,正如在如下例子中的一样:

def newfoo(arg1, arg2, *nkw, **kw):display regular args and all variable args'print 'arg1 is:', arg1 print 'arg2 is:', arg2 for eachNKW in nkw:print 'additional non-keyword arg:', eachNKWfor eachKW in kw.keys():print "additional keyword arg '%s': %s" % (eachKW, kw[eachKW])

在解释器中调用我们的函数,我们得到如下的输出:

>>> newfoo('wolf', 3, 'projects', freud=90, gamble=96)
arg1 is:wolf arg2 is:3
additional non-keyword arg: projects
additional keyword arg 'freud': 90
additional keyword arg 'gamble': 96

调用带有可变长参数对象函数

>>> newfoo(10, 20, 30, 40, foo=50, bar=60)
arg1 is: 10
arg2 is: 20
additional non-keyword arg: 30
additional non-keyword arg: 40
additional keyword arg 'foo': 50
additional keyword arg 'bar': 60

我们现在进行相似的调用;然而,我们将非关键字参数放在元组中将关键字参数放在字典中,而不是逐个列出变量参数:

>>> newfoo(2, 4, *(6, 8), **{'foo': 10, 'bar': 12})
arg1 is: 2
arg2 is: 4
additional non-keyword arg: 6
additional non-keyword arg: 8
additional keyword arg 'foo': 10
additional keyword arg 'bar': 12

最终,我们将再另外进行一次调用,但是是在函数调用之外来创建我们的元组和字典。

>>> aTuple = (6, 7, 8)
>>> aDict = {'z': 9}
>>> newfoo(1, 2, 3, x=4, y=5, *aTuple, **aDict)
arg1 is: 1
arg2 is: 2
additional non-keyword arg: 3
additional non-keyword arg: 6
additional non-keyword arg: 7
additional non-keyword arg: 8
additional keyword arg 'z': 9
additional keyword arg 'x': 4
additional keyword arg 'y': 5

注意我们的元组和字典参数仅仅是被调函数中最终接收的元组和字典的子集。额外的非关键字值‘3’以及‘x’和‘y’关键字对也被包含在最终的参数列表中,而它们不是***的可变参数中的元素。

SECTION 15 函数和函数式编程(二)相关推荐

  1. SECTION 16 函数和函数式编程(三)

    函数和函数式编程 16.1 "函数式编程" 16.2 函数式编程 16.2.1匿名函数与 lambda 16.2.2 核心笔记:lambda 表达式返回可调用的函数对象. 16.3 ...

  2. 过程或函数的副作用是_Python函数和函数式编程(两万字长文警告!一文彻底搞定函数,建议收藏!)...

    Python函数和函数式编程 函数是可重用的程序代码段,在Python中有常用的内置函数,例如len().sum()等. 在Pyhon模块和程序中也可以自定义函数.使用函数可以提高编程效率. 1.函数 ...

  3. Python中的匿名函数和函数式编程

    Python中的匿名函数和函数式编程 文章目录 Python中的匿名函数和函数式编程 一.匿名函数 匿名函数的格式: 二.函数式编程 map() filter() reduce() 区别 三.'三目运 ...

  4. python函数和函数式编程

    --以下所有内容均来自于蓝鲸运维SaaS开发实战公开课的ppt,我对其进行了整理做了笔记,便于以后查看学习. 函数 声明函数: def hello():print("hello functi ...

  5. 【数据分析R语言系列】R语言函数与函数式编程、作用域和apply 家族

    文章目录 函数与函数式编程 创建和使用函数 作用域 任意参数 函数式编程 传入和返回函数 apply 家族 apply lapply.sapply 和 vapply 函数与函数式编程 函数是代码模板. ...

  6. [js] 纯函数和函数式编程有什么关系?

    [js] 纯函数和函数式编程有什么关系? 函数式编程是一种编程思想,纯函数是这种思想的基本要实现函数式编程,我们所封装的方法应该是抽象的,应该是和外部状态无关系的,也就需要是纯函数的,这样才能保证抽象 ...

  7. 第5章 函数与函数式编程

    第5章 函数与函数式编程 凡此变数中函彼变数者,则此为彼之函数. ( 李善兰<代数学>) 函数式编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以传入函数 ...

  8. 云函数与函数式编程思想结合会产生什么?

    导语   函数式编程是一种编程范式,也就是如何编写程序的方法论.随着函数式编程被更多人广泛的关注.很多古老的函数式编程语言都重获新生,就连Java这样的老牌的编程语言都开始往函数式编程的方式开始靠近. ...

  9. 《Kotlin项目实战开发》第5章 函数与函数式编程

    第5章 函数与函数式编程 凡此变数中函彼变数者,则此为彼之函数. ( 李善兰<代数学>) 函数式编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以传入函数 ...

最新文章

  1. 计算机组成原理二进制地址码,计算机组成原理
  2. web touch 事件
  3. 百度地图- - - 鹰眼轨迹- - - -实时定位
  4. Quartz 框架快速入门(三)
  5. ROC曲线 vs Precision-Recall曲线
  6. AC_Automata模板
  7. pq 中m函数判断嵌套_压轴题的热点,二次函数与几何的结合,谁会谁吃香
  8. 在CentOS7上安装配置Corosync高可用集群过程全记录
  9. php学生选课系统设计网站作品
  10. SqlServer和Oralce保留几位小数以及当末尾小数为0也显示
  11. 计算机更新bios,小编教你如何升级bios
  12. 计算机没wps云档怎么办,WPS云空间多大?WPS云文档空间已经用满怎么办?删数据或买VIP-太平洋电脑网...
  13. [Spark版本更新]--Spark-2.4.0 发布说明
  14. 用scrapy框架爬取拉勾网招聘信息
  15. BlenderGIS插件安装和排错
  16. oneDrive 5T网盘空间申请教程
  17. 为什么局域网IP通常以192.168开头而不是1.2或者193.169?
  18. 那些35岁的程序员哪里去了?
  19. 【Azure Data Platform】ETL工具(22)——Azure Databricks与ADF整合
  20. matlab实现LSB图像水印的嵌入与提取

热门文章

  1. 英语商务对话和英语商务谈判技巧
  2. Python+OpenCV 调用手机摄像头并实现人脸识别
  3. NYOJ 925 国王的烦恼
  4. 对比学习(Contrastive Learning)中的损失函数
  5. js仿苹果风格弹出框alert插件
  6. VGA原理详解与verilog实现RGB888彩条(二)
  7. 美国圣克鲁斯大学计算机科学,加州大学圣克鲁兹分校最热门专业,了解一下?...
  8. Vue3不支持eventBus
  9. 谷歌打开后开始页面被hao123篡改
  10. 关于「微信小程序」背后的故事