函数是对程序逻辑进行结构化或过程化的一种编程方法。

Python的函数返回值
当什么也不返回时,返回了None
和大多数语言一样,Python返回一个值或对象。只是在返回容器对象时,看起来像返回多个对象。
这样在操作的时候显得很灵活,虽然它本质上只是反悔了一个对象。

调用函数
我们用一对圆括号电泳函数。任何输入的参数都应该放在括号中。

关键字参数
这个概念是针对函数调用的,比如我们有这样的函数

def fun(value, count):
  fun_suite

我们可以标准调用:

fun(12,20)

也可以关键字调用

fun(value = 12, count = 20)

或者

fun(count = 20, value =12)

这样可以丰富调用的方法。另外当参数允许“缺失”的时候,也可以用关键字参数。这取决于函数的默认参数。

参数组
Python同样允许程序员执行一个没有显式定义参数的函数,相应的方法是通过一个把元组或字典作为参数传递给函数(元组是非关键字调用,字典是关键字调用)。基本上,可以把所有参数放进一个元组或字典中,仅仅用这些装有参数的容器来调用一个函数,而不必显式地将它们放在函数调用中:

func(*tuple_grp_nonkw_args, **dict_grp_kw_args)

其中,tuple_grp_nonkw_args是以元组形式体现的非关键字参数组,dict_grp_kw_args是装有关键字参数的字典。这样的特性允许把变量放在元组和/或字典里,并在没有显式地对参数进行逐个声明的情况下调用函数。
当然也可以给出形参:

func(positional_args, keyword_args,
*tuple_grp_nonkw_args, **dict_grp_kw_args)

该语法的所有参数都是可选的,在单独函数调用时,每个参数都是独立的。可以有效取代Python1.6以前的apply()内建函数。
如下例:

from operator import add, sub
from random import randint, choice ops = {'+': add, '-': sub}
MAXTRIES = 2 def doprob():
op = choice('+-')
nums = [randint(1,10) for i in range(2)]
nums.sort(reverse = True)
ans = ops[op] (*nums) # *表示后面这个变量是个元组,这一句用了前缀操作符
pr = '%d %s %d = '%(nums[0],op,nums[1])
oops = 0
while True:
try:
if int(raw_input(pr)) == ans:
print 'correct'
break
if oops == MAXTRIES:
print 'answer\n%s%d' %(pr, ans)
else:
print 'incorrect... try again'
oops += 1
except (KeyboardInterrupt, \
EOFError, ValueError) :
print 'invalid input... try again' def main():
while True:
doprob()
try:
opt = raw_input('Again? [y]').lower()
if opt and opt[0] == 'n':
break
except (KeyboardInterrupt, EOFError):
break if __name__ == '__main__':
main()

上面带有注释那一行,在Python1.6以前,要写成apply(ops[op], nums),而不是ops[op](*nums)

创建函数
def语句
语法如下:

def function_name(arguments):
  "function_documentation_string"
  function_body_suite

前向引用,要在使用前定义函数。

函数属性
命名空间与作用域的关系
可以获得每个Python模块,类,和函数中任意的名字空间。可以在模块foo和bar里都有名为x的一个变量,但是在将这两个模块导入你的程序后,仍然可以使用这两个变量。所以,即使在两个模块中使用了相同的变量名字,也是安全的,因为句点属性标识对于两个模块意味了不同的命名空间,比如说,在这段代码中没有名字冲突:

import foo, bar
print foo.x + bar.x

函数属性是Python另外一个使用了句点属性标识并拥有名字空间的领域。
名字空间和作用域的关系,在之前的笔记 模块 这一部分里有详细叙述。

内嵌函数
在函数体内创建另外一个函数(对象)是完全合法的。这种函数叫做内部/内嵌函数。因为现在Python支持静态地嵌套域,内部函数实际上是很有用的。
最明显的创造内部函数的方法是在外部函数的定义体内定义函数,如:

def foo():
  def bar():
    print 'bar() called'
  print 'foo() called'
  bar()
foo()
bar()

结果是:

foo() called
bar() called
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
bar()
NameError: name 'bar' is not defined

传递函数
Python的函数就和其他对象一样,函数是可以被引用的,也可以作为参数传入函数,以及作为列表和字典等等容器对象的元素。
函数有个独一无二的特征使它同其他对象区分开来,那就是函数是可调用的。
因为所有的对象都是通过引用来传递的,函数也不例外。当对一个变量赋值时,实际上是将相同对象的引用赋值给这个变量。如果对象是函数的话,这个对象所有的别名都是可调用的。

>>> def foo():
print 'in foo()' >>> bar = foo
>>> bar
<function foo at 0x02B3A0B0>
>>> bar()
in foo()
>>> bar = foo()
in foo()
>>> bar
>>> print bar

当我们把foo赋值给bar时,bar和foo引用了同一个函数对象,所以能以和调用foo()相同的方式调用。foo是函数对象的引用,foo()是函数对象的调用。

同时,函数也可以作为参数传入其他函数来进行调用

>>> def bar(func):
func() >>> bar(foo)
in foo()

注意,是将函数对象的引用作为参数,而不是函数对象的调用。

形式参数
Python函数的形参集合由在调用时要传入函数的所有参数组成,这参数与函数声明中的参数列表精确的配对。这些参数包括了所有必要参数(如果是标准调用则用正确的定位顺序来传入函数,如果是关键字调用则不一定按顺序传入)以及所有含有默认值,函数调用时不必要指定的参数。(声明函数时创建的)局部命名空间为各个参数值,创建了一个名字,一旦函数开始执行,即能访问这个名字。
位置参数
位置参数必须以在bewilder调用函数中定义的准确顺序来传递。另外,没有任何默认参数的话,传入函数的参数的精确的数目必须和声明的数字一致。位置参数也就是我们熟悉的标准化参数
默认参数
对于默认参数,如果在函数调用时我们没有提供值,就预先使用定义的标准值,如下:

>>> def taxMe(cost, rate=0.0825):
return cost + (cost * rate) >>> taxMe (100)
108.25
>>> taxMe (100, 0.05)
105.0

默认参数让程序的健壮性上升到极高的级别,因为它们补充了标准位置参数没有提供的一些灵活性。
我们声明时,所有的必需参数都要在默认参数之前。否则,在混合模式下,解释器将无法知道如何匹配参数。当然,如果使用关键字参数的方式,是可以改换顺序的,前提是所有没给默认值的参数都传入了值。

可变长度的参数
可能会有需要函数处理可变数量参数的情况。这时可以使用可变长度的参数列表。变长的参数在函数声明中不是显式命名的,因为参数的数目在运行时是未知的,这和常规参数(位置和默认)明显不同,床柜参数都是在函数声明中命名的。由于函数调用提供了关键字以及非关键字两种参数类型,Python用两种方式来支持变长参数。

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

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

星号操作符之后的形参将作为元组传递给函数,元组保存了所有传递给函数的“额外”的参数(匹配了所有位置和具名参数后剩余的)。如果没有给出额外参数,元组为空。
在我们之前的函数调用中,如果给出了不正确的函数参数数目,就会产生一个TypeError异常。通过末尾增加一个可变的参数列表变量,我们就能处理当超过数目的参数被传入函数的情形,因为所有的额外(非关键字)参数会被添加到变量参数元组。而和位置参数必须放在关键字参数之前一样的原因,所有的形式参数必须先于非正式参数之前出现。

def 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:', eachXtrArg

运行结果如下:

>>> tupleVarArgs('abc')

formal arg 1: abc
formal arg 2: defaultB
>>> tupleVarArgs(23,4.56) formal arg 1: 23
formal arg 2: 4.56
>>> tupleVarArgs('abc',123,'xyz',456.789) formal arg 1: abc
formal arg 2: 123
another arg: xyz
another arg: 456.789

关键字变量参数(字典)
在我们有不定数目的或者额外集合的关键字的情况中,参数被放入一个字典中,字典中键为参数名,值为相应的参数值。
语法为:

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

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

>>> def dictVarArgs(arg1,arg2='defaultB',**theRest):
  'display 2 regular args and keyword variable args'
  print 'formal arg1:', arg1
  print 'formal arg2:', arg2
  for 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

关键字和非关键字可变长参数都有可能用在同一个函数中,只要关键字字典是最后一个参数并且非关键字元组先于它之前出现。

调用带有可变长参数对象函数
将展示一些使用它的例子:

>>> 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:', eachNKW
for 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 'gamble': 96
additional keyword arg 'freud': 90
>>> 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 'y': 5
additional keyword arg 'x': 4
additional keyword arg 'z': 9

2015/9/17 Python基础(13):函数的更多相关文章

  1. python基础13 ---函数模块3(正则表达式)

    正则表达式 一.正则表达式的本质 1.正则表达式的本质(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的 ...

  2. python基础(13):函数名的使用、第一类对象、闭包、迭代器

    1. 函数名的运用 函数名是⼀个变量,但它是⼀个特殊的变量,与括号配合可以执⾏函数的变量. 1.1 函数名的内存地址 def func(): print("呵呵") print(f ...

  3. python基础——filter函数

    python基础——filter函数 Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函 ...

  4. 十三. Python基础(13)--生成器进阶

    十三. Python基础(13)--生成器进阶 1 ● send()方法 generator.send(value) Resumes the execution, and "sends&qu ...

  5. 八. Python基础(8)--函数

    八. Python基础(8)--函数 1 ● 函数返回布尔值 注意, 自定义的函数也可以是用来作逻辑判断的, 例如内置的startswith()等函数. def check_len(x):     ' ...

  6. python基础——匿名函数

    python基础——匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便.  在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时 ...

  7. python基础——返回函数

    python基础——返回函数 函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回.  我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_ ...

  8. python基础——sorted()函数

    python基础——sorted()函数 排序算法 排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个d ...

  9. python基础——匿名函数及递归函数

    python基础--匿名函数及递归函数 1 匿名函数语法 匿名函数lambda x: x * x实际上就是: def f(x): return x * x 关键字lambda表示匿名函数,冒号前面的x ...

随机推荐

  1. zookeeper:一.zookeeper集群安装

    1.zookeeper简介2.安装zookeeper2.1 安装环境准备2.2 安装zookeeper2.2.1.解压zookeeper压缩包到/opt/zookeeper2.2.2.编辑zookee ...

  2. Thunder团队第一周 - Scrum会议6

    Scrum会议6 小组名称:Thunder 项目名称:爱阅app Scrum Master:苗威 工作照片: 参会成员: 王航:http://www.cnblogs.com/wangh013/ 李传康 ...

  3. 文件异步上传-ajaxFileUpload

    $.ajaxFileUpload是一个jquery插件 文章:jQuery插件之ajaxFileUpload

  4. DAY2敏捷冲刺

    站立式会议 工作安排 (1)服务器配置 (2)数据库连接 (3)页面创意 燃尽图 代码提交记录 感想 林一心:centos配置服务器真的算是一个不小的坑,目前数据库配置清楚,脚本部署好明天测试交互,还 ...

  5. 《学习OpenCV》课后习题解答4

    题目:(P104) 练习使用感兴趣区域(ROI).创建一个210*210的单通道图像并将其归0.在图像中使用ROI和cvSet()建立一个增长如金字塔状的数组.也就是:外部边界为0,下一个内部边界应该 ...

  6. 3ds max启动慢怎么办?

      有时候启动3ds max的时候一直卡在启动界面进不去怎么办?   在百度上搜到了下面这个解决方案,试了下还真有用:   具体就是进到这个文件夹,然后分别进入第一个和第三个文件夹删掉autodesk ...

  7. Jenkins系列-Jenkins介绍与部署

    Jenkins是什么? Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测 ...

  8. Maven jeetsite项目 搭建

    , 一直没有系统的总结一下Maven的知识,今天,想从网上找一个Maven的项目,练练手,顺便学习一下maven的原理 和布局. 官网:http://www.jeesite.com/ 没想到,上来就给 ...

  9. 2011 Multi-University Training Contest 6 - Host by JLU

    打了4hours,做出一道题...太菜了.rank:45/107 开场看B,题目看不懂...3hours半才发现i<=N-1,不是i<=x-1.然而还是不会. 看到J有人过了,发现是个简单 ...

  10. 【bzoj4401】块的计数 结论题

    题目描述 给出一棵n个点的树,求有多少个si使得整棵树可以分为n/si个连通块. 输入 第一行一个正整数N,表示这棵树的结点总数,接下来N-1行,每行两个数字X,Y表示编号为X的结点与编号为Y的结点相 ...