函数可以计算出一个返回值。作用:最大化代码重用,最小化代码冗余,流程的分解。
一、函数编写1、基本编写def是可执行的代码,实时执行的(Python中所有语句都是实时执行的)。if,while,def可嵌套,可以出现在任何地方,但往往包含在模块文件中。def创建了一个对象并将其赋值给某一个变量名。return将一个结果对象发送给调用者,如果函数中没有return语句,就会自动返回None对象函数是通过赋值(对象引用)传递的。参数通过赋值传递给函数。global声明了一个模块级的变量并被赋值。参数,返回值以及变量并不是声明def语句将创建一个函数对象并将其赋值给一个变量名。一般格式如下:def <name>(arg1,age2,...,agrN): <statements> return <value>函数主体往往都包含了一个return语句(不是必须的),如果它没有出现,那么函数将会在控制流执行完函数主体时结束,技术上,没有返回值的函数自动返回了none对象。return可以在函数主体中的任何地方出现。它表示函数调动的结束,并将结果返回至函数调用处。函数通过嵌套到if语句中去实现不同的函数定义的格式:if test: def func(): ...else: def func()2、编写函数时的参数设置def func(name1,name2) 函数 常规参数:通过位置或变量名进行匹配def func(name=value) 函数 默认参数值:如果没有在调用中传递的话,就是用默认值def func(*name) 函数 匹配并收集(在元组中)所有包含位置的参数 通过一个把元组(非关键字参数)作为参数组传递给函数def func(**name) 函数 匹配并收集(在字典中)所有包含位置的参数。过一个把字典(关键字参数)作为参数组传递给函数3、函数的属性
函数的属性本质上是函数本地作用域里的变量,包括函数内内嵌的函数函数属性是python 另外一个使用了句点属性标识并拥有名字空间的领域>>> def testjin():... name='jin'... >>> testjin.__doc__='test'>>> testjin.version='0.1' >>> help(testjin)Help on function testjin in module __main__:testjin()
test>>> print testjin.version0.1>>> print testjin.__doc__test>>> print testjin.name Traceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: 'function' object has no attribute 'name' #这里没想明白为什么不能访问?这个是因为函数内命名空间还没有建立吗?是因为函数体还没有被创建.>>> testjin()>>> testjin.nameTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: 'function' object has no attribute 'name'先运行函数,在访问里面的变量也不能访问,这点和module,class不一样>>> class classjin():... name='jin'... >>> print classjin.namejin类可以,模块可以>>> testjin.__dict__{'version': '0.1'}二、作用域[变量作用域]
python作用域:变量定义以及查找的地方1、作用域法则Python创建,改变或者查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行。作用域这个术语指的就是命名空间。也就说,在代码中变量名被赋值的位置决定了这个变量名能被访问到的范围一个函数所有变量名都与函数的命名空间相关联。*def内定义变量名def内使用*def之中的变量名与def之外的变量名不发生冲突,使用别处相同的变量名也没问题。x=99def func() x=88函数定义了本地作用域,而模块定义了全局作用域。两作用域关系。*内嵌的模块是全局作用域:模块的全局变量就成为了一个模块对象的属性。*全局作用域的作用范围仅限单个文件:不要被全局迷惑,这里的全局是一个文件的顶层的变量名,仅对这个文件内部的代码而言是全局。Python中,没有一个无所不包的情景文件作用域。替代的方法是,变量名由模块文件隔开,必须精准地导入一个模块文件才能使用这文件中定义的变量名,*每次对函数的调用都创建了一个新的本地作用域。*赋值的变量名除声明为全局变量,否则均为本地变量。*所用的变量名都可以归纳为本地,全局,或者内置。(内置:python预定义的__builtin__模块提供的)2、变量名解析:LEGB原则对一个def语句*变量名引用分为三个作用域进行查找:首先查找本地(函数内,如果有),之后全局,最后内置。*默认情况下,变量名赋值会创建或改变本地变量*全局声明将赋值变量名映射到模块文件内部的作用域。3、内置作用域需要导入__builtin__ >>> import __builtin__>>> dir(__builtin__)里面前一半是内置异常,后一半是内置函数4、globalglobal语句包含关键字global*全局变量是位于模块文件内部顶层的变量名*全局变量如果是在函数内部被赋值的话,并需经过声明,方式 global 变量名*全局变量名在函数的内部不经过声明也可以变引用def testjin(): global name name='jin'testjin()
print name这里要注意,函数testjin()要执行后,函数内testjin()中局部变量name才会提升为全局变量,函数外才能访问但是一般都不用这种临时的方式,全局的就在全局定义,局部的就在局部定义5、闭包[了解]
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)[也就是包含函数的函数作用域]的变量进行引用,那么内部函数就被认为是闭包closure。定义在外部函数内的但由内部函数引用或者使用的变量被称为[自由变量]。闭包将内部函数自己的代码和作用域以及外部函数的作用域结合起来。闭包的词法变量不属于全局名字空间或者局部的--而属于其他的名字空间,带着“流浪"的作用域。回调就是函数。闭包也是函数,但是他们能携带一些额外的作用域。它们仅仅是带了额外特征的函数……另外的作用域。将函数1放到一个函数2中,函数2 return 函数1这个对象。函数1会引用函数2作用域中的变量【引用外部但不是全局作用域】def 函数2(argv2): name=0 def 函数1(argv1): name=+1 return 函数1testdef=函数2(函数2参数) 有点类似于类的实例有点不同的是我们能够做些原来需要我们写一个类做的事,并且不仅仅是要写,而且必需覆盖掉这个类的__call__()特别方法来使他的实例可调用。这里我们能够使用一对函数来做这事。现在,在很多情况下,类是最适合使用的。def counter(start_at=0): count = [start_at] def incr(): count[0] += 1 return count[0] return incrcounter()做的唯一一件事就是接受一个初始化的的值来开始计数,并将该值赋给列表count唯一一个成员。然后定义一个incr()的内部函数。通过在内部使用变量count,我们创建了一个闭包。因为它现在携带了整个counter()作用域。incr()增加了正在运行的count然后返回它。然后最后的魔法就是counter()返回一个incr,一个(可调用的)函数对象。如我们交互地运行这个函数,我们将得到如下的输出---------注意这看起来和实例化一个counter对象并执行这个实例有多么相似。>>> count = counter(5)>>> print count()6>>> print count()7>>> count2 = counter(100)>>> print count2()101闭包和修饰符也有类似,修饰符在函数前后做准备或者清理操作,闭包是在函数中引用外部作用域变量做操作并返回做操作的函数6、作用域和lamba
三、函数调用和传递参数
1、函数调用func(value1,value2) 调用者 常规参数,通过位置进行匹配func(name=value) 调用者 关键字参数,通过变量名匹配func(*name) 调用者 可变长度的参数,以name传递所有的对象,并作为独立的基于位置的参数,通过一个把元组(非关键字参数)作为参数组传递给函数func(**name) 调用者 可变长度的参数,以name成对的传递所有的关键字/值,并作为独立的关键字的参数,过一个把字典(关键字参数)作为参数组传递给函数2、函数参数说明
参数传递:传递给函数作为其输入对象的方式*参数的传递是通过自动将对象赋值给本地变量来实现的。
*在函数内部的参数名的赋值不会影响调用者。*改变函数的可变对象参数的值也许会对调用者有影响。换句话说,因为参数是简单的通过赋值进行对象的传递,函数能够改变传入的可变对象,因此其结果会影响调用者。*不可变参数是“通过值”进行传递。像整数和字符串这样的对象是通过对象引用而不是拷贝进行传递的,但是因为你无论如何都不可能在原处改变不可变对象,实际的效果就是很像创建了一份拷贝。可变对象是通过“指针”进行传递的。参数在ptyhon中总是通过赋值进行传递,传入的对象赋值给了在def头部的变量名。尽管这样,在模型的上层,python提供了额外的工具,
该工具改变了调用过中,赋值时参数对象匹配在头部的参数名的优先级。这些工具是可选的。默认情况下,参数是通过其位置进行匹配的,从左到右,而且必须精确地传递和函数头部参数名一样多的参数。还能够定义变量名进行匹配,默认参数值(arg2=10),以及对于额外参数的容器必须要根据变量名匹配对象,匹配完成后在传递机制的底层依然是赋值。这些工具对于边写库文件的人来说,要比应用程序开发者更用有。3、参数设置规则
###############################(1)、位置参数(2)、默认参数(3)、关键字参数可变长度参数(4)、* 非关键字可变参数(元组)(5)、** 关键字可变参数(字典)###############################【1】位置参数[行参]:从左到右进行匹配【2】关键字参数:通过参数名进行匹配。【调用时】【调用者】可以定义那个函数接受这个值,通过在调用时使用参数的变量名,使用name=value这种语法。【3】*默认参数:为没有传入值得参数定义参数值【定义函数时】如果调用时传入的值过于少的话,函数能够为参数定义接受的默认值,在函数定义中使用name=value【4】*可变参数:收集任意多基于位置或关键字的参数1)以*开头,收集任意多的额外参数2)**可变参数:传递任意多的基于位置或关键字的参数。【调用时】调用者能够在使用*语法去将参数集合打撒,分成参数。这个*与函数头部的*恰恰相反。在函数头部他意味着收集任意多的参数,而在调用者中意味着传递任意多的参数。总结与特定模式有关的语法:
语法 位置 解释func(value1,value2) 调用者 常规参数,通过位置进行匹配func(name=value) 调用者 关键字参数,通过变量名匹配func(*name) 调用者 可变长度的参数,以name传递所有的对象,并作为独立的基于位置的参数,通过一个把元组(非关键字参数)作为参数组传递给函数func(**name) 调用者 可变长度的参数,以name成对的传递所有的关键字/值,并作为独立的关键字的参数,过一个把字典(关键字参数)作为参数组传递给函数def func(name1,name2) 函数 常规参数:通过位置或变量名进行匹配
def func(name=value) 函数 默认参数值:如果没有在调用中传递的话,就是用默认值def func(*name) 函数 匹配并收集(在元组中)所有包含位置的参数 通过一个把元组(非关键字参数)作为参数组传递给函数def func(**name) 函数 匹配并收集(在字典中)所有包含位置的参数。过一个把字典(关键字参数)作为参数组传递给函数python 中用默认值声明变量的语法是所有的位置参数必须出现在任何一个默认参数之前。【注意】
def func(posargs, defarg1=dval1, defarg2=dval2,...): "function_documentation_string" function_body_suite每个默认参数都紧跟着一个用默认值的赋值语句。如果在函数调用时没有给出值,那么这个赋值就会实现4、任意参数
*和** 让函数支持接收任意数目的参数。收集参数第一种用法:在函数定义中,在元组中收集不匹配的位置参数【1】非关键字可变长参数(元组)当函数被调用的时候,所有的形参(必须的和默认的)都将值赋给了在函数声明中相对应的局部变量。剩下的非关键字参数按顺序插入到一个元组中便于访问def function_name([formal_args,] *vargs_tuple): "function_documentation_string" function_body_suite星号操作符之后的形参将作为元组传递给函数,元组保存了所有传递给函数的"额外"的参数(匹配了所有位置和具名参数后剩余的)。如果没有给出额外的参数,元组为空除位置参数和默认参数外的其他参数放入一个元组。正如我们先前看见的,只要在函数调用时给出不正确的函数参数数目,就会产生一个TypeError异常。通过末尾增加一个可变的参数列表变量,
【我们就能处理当超出数目的参数被传入函数的情形】,因为所有的额外(非关键字)参数会被添加到变量参数元组。正如预料的那样,由于和位置参数必须放在关键字参数之前一样的原因,所有的形式参数必须先于非正式的参数之前出现>>> def tupleVarArgs(arg1, arg2='defaultB', *theRest):... print 'formal arg 1:', arg1... print 'formal arg 2:', arg2... for eachXtrArg in theRest:... print 'another arg:', eachXtrArg... >>> tupleVarArgs('abc')formal arg 1: abcformal arg 2: defaultB>>> tupleVarArgs(23, 4.56)formal arg 1: 23formal arg 2: 4.56>>> tupleVarArgs('abc', 123, 'xyz', 456.789)formal arg 1: abcformal arg 2: 123another arg: xyzanother arg: 456.789【2】关键字变量参数(Dictionary)
在我们有不定数目的或者额外集合的关键字的情况中,参数被放入一个字典中,字典中键为参数名,值为相应的参数值。为什么一定要是字典呢?因为为每个参数-参数的名字和参数值--都是成对给出---用字典来保存这些参数自然就最适合不过了。这给出使用了变量参数字典来应对额外关键字参数的函数定义的语法:def function_name([formal_args,][*vargst,] **vargsd): function_documentation_string function_body_suite为了区分关键字参数和非关键字非正式参数,使用了双星号(**)。**是被重载了的以便不与幂运算发生混淆。关键字变量参数应该为函数定义的【最后一个参数】,带**。我们现在展示一个如何使用字典的例子:>>> def dictVarArgs(arg1, arg2='defaultB', **theRest): ... 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: 1220formal arg2: 740.0Xtra arg c: grail>>> dictVarArgs(1220, 740.0) formal arg1: 1220formal arg2: 740.0>>> dictVarArgs(1220) formal arg1: 1220formal arg2: defaultB>>> dictVarArgs() Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: dictVarArgs() takes at least 1 argument (0 given)>>> dictVarArgs(arg2='tales', c=123, d='poe', arg1='mystery')formal arg1: mysteryformal arg2: talesXtra arg c: 123Xtra arg d: poe>>> dictVarArgs('one', d=10, e='zoo', men=('freud', 'gaudi'))formal arg1: oneformal arg2: defaultBXtra arg men: ('freud', 'gaudi')Xtra arg e: zooXtra arg d: 10关键字和非关键字可变长参数都有可能用在同一个函数中,只要关键字字典是最后一个参数并且非关键字元组先于它之前出现,正如在如下例子中的一样。位置参数,默认参数,非关键字可变参数,关键字可变参数全有的实例my name is: jin>>> def testjin(k1,k2='jin',*k3,**k4):... print '1st k1 is:%s' % k1 ... print 'default K2 is:%s' % k2 ... for i in k3:... print 'tup k3 is:%s' % i ... for n in k4.keys():... print 'dict k4 is:%s' % n >>> testjin(1)1st k1 is:1default K2 is:jin>>> testjin(1,'a','b','d',name='diege',age='28')1st k1 is:1default K2 is:atup k3 is:btup k3 is:ddict k4 is:agedict k4 is:name四、函数嵌套和装饰器
1、函数嵌套在函数体内创建另外一个函数(对象)是完全合法的。这种函数叫做内部/内嵌函数。最明显的创造内部函数的方法是在外部函数的定义体内定义函数(用def 关键字),如在:>>> def foo(): ... def bar(): ... print 'bar() called'... print 'foo() called' ... bar()... >>> foo() foo() calledbar() called>>> bar()Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'bar' is not defined放入inner.py模块# python26 inner.pyfoo() calledbar) calledTraceback (most recent call last): File "inner.py", line 7, in ? bar()NameError: name 'bar' is not defined内部函数一个有趣的方面在于整个函数体都在外部函数的作用域之内。如果没有任何对bar()的外部引用,那么除了在函数体内,
任何地方都不能对其进行调用,这就是在上述代码执行到最后你看到异常的原因.另外一个函数体内创建函数对象的方式是使用lambda语句2、函数(方法)装饰器
http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html1)什么是装饰器装饰器实际就是函数。他接受函数对象,也可以有自己的参数。一般说来,当包装一个函数的时候,会最终会调用它。最棒的是我们能在包装的环境下在合适的时机调用它。我们在执行函数之前,可以运行些预备代码,也可以在执行代码之后做些清理工作。也就是做预备或者清理工作。可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。例如,可以用装饰器来:(1)引入日志(2)增加计时逻辑来检测性能(3)给函数加入事务的能力个人设想:定义一个函数记录日志 然后在有需要的地方用这个记录日志的函数做装饰器去记录其他函数的执行情况。2)修饰符语法
面向切面的编程(Aspect-Oriented Programming),与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。装饰器背后的主要动机源自python面向切面的编程。装饰器是在函数调用之上的修饰。这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。紧跟着装饰器声明的是被修饰的函数,和被装饰函数的可选参数。装饰器看起来会是这样: @decorator(dec_opt_args) def func2Bdecorated(func_opt_args): passclass MyClass(object):
@staticmethod def staticFoo(): pass3)修饰符堆叠装饰器可以如函数调用一样“堆叠“起来,这里有一个更加普遍的例子,使用了多个装饰器:装饰器可以试一个也可以是多个,多个装饰器在应用时的顺序与指定的顺序相反@deco2@deco1def func(arg1, arg2, ...): pass这和创建一个组合函数是等价的。def func(arg1, arg2, ...): passfunc = deco2(deco1(func))4)有参数和无参数的装饰器
【修饰符本身是函数所以可以有参数】没有参数的情况,一个装饰器如:@decodef foo(): pass等同foo = deco(foo)带参数的装饰器decomaker()
@decomaker(deco_args)def foo(): pass等同foo = decomaker(deco_args)(foo)需要自己返回以函数作为参数的装饰器。换句话说,decomaker()用deco_args 做了些事并返回函数对象1个含有多个装饰器的例子,其中的一个装饰器带有一个参数@deco1(deco_arg)@deco2def func(): passThis is equivalent to:这等价于:func = deco1(deco_arg)(deco2(func))修饰符举例#!/bin/env pythonfrom time import ctime, sleep
def tsfunc(func): #定义一个将做修饰符的函数,里面包含了一个子函数打印调修饰的对象和调用的时间,修饰符函数返回这个子函数对象 def wrappedFunc(): print '[%s] %s() called' % (ctime(), func.__name__) return func() return wrappedFunc@tsfunc #使用前面定义的函数修饰foo函数,foo函数什么都没做
def foo(): passfoo() #调用被修饰过的函数foo
sleep(4)for i in range(2): #连续3次,间隔1秒调用foo函数
sleep(1) foo()5)内置的装饰器内置的装饰器有三个,分别是staticmethod、classmethod和property,作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数,所以静态方法和类方法的用处并不是太多,除非你想要完全的面向对象编程。而属性也不是不可或缺的,使用property,staticmethod和classmethod的频率也非常低。property属于新式类的特性python版本大于2.2class HideX(object): def __init__(self, x): self.x = x @property def x(): def fget(self): return ~self.__x def fset(self, x): assert isinstance(x, int), '"x" must be an integer!' self.__x = ~x return locals()6)其他模块包含的装饰器functools模块wraps(wrapped[, assigned][, updated]): total_ordering(cls):五、函数式编程【了解】
掌握lambda、filter()、map()、reduce()即可Python 不是也不大可能会成为一种函数式编程语言,但是它支持许多有价值的函数式编程语言构建。1.匿名函数与lambdapython 允许用lambda 关键字创造匿名函数。匿名是因为不需要以标准的方式来声明,比如说,使用def 语句。(除非赋值给一个局部变量,这样的对象也不会在任何的名字空间内创建名字.)然而,作为函数,它们也能有参数。一个完整的lambda“语句”代表了一个表达式,这个表达式的定义体必须和声明放在同一行。我们现在来演示下匿名函数的语法:lambda [arg1[, arg2, ... argN]]: expression参数是可选的,如果使用的参数话,参数通常也是表达式的一部分。核心笔记:lambda 表达式返回可调用的函数对象。
用合适的表达式调用一个lambda 生成一个可以像其他函数一样使用的函数对象。它们可被传入给其他函数,用额外的引用别名化,作为容器对象以及作为可调用的对象被调用(如果需要的话,可以带参数)。当被调用的时候,如给定相同的参数的话,这些对象会生成一个和相同表达式等价的结果。对比def true(): return True或def true(): return True使用lambda 的等价表达式(没有参数,返回一个True)为:lambda :True这里用它赋值看起来非常有用。相似地,我们可以把lambda 表达式赋值给一个如列表和元组的数据结构,其中,基于一些输入标准,我们可以选择哪些函数可以执行,以及参数应该是什么。(在下个部分中,我们将展示如何去使用带函数式编程构建的lambda 表达式。def add(x, y): return x + y lambda x, y: x + y2 内建函数apply()、filter()、map()、reduce()map/filter/reduce,都是对一个集合进行处理,filter很容易理解用于过滤,map用于映射,reduce用于归并内建函数 描述apply(func[, nkw][, kw])【已淘汰】filter(func, seq) 【部分功能被列表取代】调用一个布尔函数func 来迭代遍历每个seq 中的元素; 返回一个使func 返回值为ture 的元素的序列。map(func, seq1[,seq2...])【部分功能被列表取代】 将函数func用于给定序列(s)的每个元素,并用一个列表来提供返回值;
func为None, func表现为一个身份函数,返回一个含有每个序列中元素集合的n个元组的列表。reduce(func, seq[, init]) 将二元函数作用于seq 序列的元素,每次携带一对(先前的结果以及下一个序列元素),连续的将现有的结果和下雨给值作用在获
得的随后的结果上,最后减少我们的序列为一个单一的返回值;如果初始值init 给定,第一个比较会是init 和第一个序列元素而不是序列的头两个元素。1)filter(func, seq)
给定一个对象的序列和一个“过滤”函数,每个序列元素都通过这个过滤器进行筛选, 保留函数返回为真的的对象。filter 函数为已知的序列的每个元素调用给定布尔函数。每个filter 返回的非零(true)值元素添加到一个列表中。返回的对象是一个从原始队列中“过滤后”的队列。为真的队列。个人总结:通过一个函数对一个序列操作,返回操作为真的序列。返回一个序列, 包含了给定序列中所有调用function(item)后返回值为true的元素。目的:基于某一测试函数过滤出一些元素。列表模拟from random import randint as riprint [n for n in [ri(1,99) for i in range(9)] if n%2]>>> range(-5,5)[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]>>> filter((lambda x:x>0),range(-5,5))[1, 2, 3, 4]这个等效于for range:if语句2)map(func, seq1[,seq2...])
map(函数,传入函数的序列对象)个人总结:#多个序列相同位置组成的元组作参数传递给函数,返回函数处理后的返回值组成的列表。为每个元素一次调用function(item)并将返回值组成一个链表返回.使用内置工具map,map函数会对一个序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表。形式更一般的map()能以多个序列作为其输入。如果是这种情况, 那么map()会并行地迭代每个序列。将每个序列相同位置的元素组成一个元组传递给函数。函数的参数个数必须和序列个数一致, 执行时会一次用各个序列上对应的元素来调用函数(如果某些序列比其他短,则用None代替).>>> def inc(x):return x+10... >>> L=[1,2,3,4,5]>>> map(inc,L)[11, 12, 13, 14, 15]备注:map函数另外一个用法,把序列的元素配对起来,但是如果参数长度,不同则会为较短的序列用None补齐。map(None, seq1,seq2) 最简单的形式>>> aList=[1,2,3]>>> bList=['a','b','c']>>> map(None,aList,bList)[(1, 'a'), (2, 'b'), (3, 'c')]map嵌套lambda >>> map((lambda x:x+3),L)[4, 5, 6, 7, 8]def map_imp(function, sequence) :
if function is None: return list(sequence) retvals = [] for element in sequence: if (function(element)): retvals.append(element) return retvals当map的第一个参数为class类型时,返回的是用第二个参数创建的class类的实例。
def map_imp2(class,sequence): retvals = [] if (class(sequence)): retvals.append([class(sequence)]) return retvals 3)reduce 使用了一个二元函数(一个接收带两个值作为输入,进行了一些计算然后返回【一个值】作为输出),一个序列,和一个可选的初始化器,卓有成效地将那个列表的内容“减少”为一个单一的值,如同它的名字一样。在其他的语言中,这种概念也被称作为折叠。个人总结:通过一个函数对一个序列操作返回一个值。对每对元素都应用函数并运行到最后结果.返回一个单值, 首先以序列的前两个元素调用函数, 再以返回的值和第三个参数调用, 一次执行下去.如果我们想要试着用纯python 实现reduce(), 它可能会是这样:
def reduce(bin_function,seq,init=None) if init is None: # initializer? res = lseq.pop(0) # no else: res = init # yes for item in lseq: # reduce sequence res = bin_func(res, item) # apply function return res # return result这里两个reduce调用,计算在一个列表中所有元素加起来和以及乘起来的乘积>>> reduce((lambda x,y:x+y),[1,2,3,4])10>>> reduce((lambda x,y:x*y),[1,2,3,4]) 243、偏函数应用【略】
六、递归
如果函数包含了对其自身的调用,该函数就是递归的七、迭代器迭代器介绍的还不错的文章:http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html1、迭代器介绍Iterator是迭代器的意思,它的作用是一次产生一个数据项,直到没有为止。这样在 for 循环中就可以对它进行循环处理了。那么它与一般的序列类型(list, tuple等)有什么区别呢?它一次只返回一个数据项,占用更少的内存。但它需要记住当前的状态,以便返回下一数据项。它是一个有着next()方法的对象。而序列类型则保存了所有的数据项,它们的访问是通过索引进行的。迭代器和iter()函数
根本上说, 迭代器就是有一个 next()方法的对象, 而不是通过索引来计数. 当你或是一个循环机制(例如 for 语句)需要下一个项时, 调用迭代器的next()方法就可以获得它。条目全部取出后, 会引发一个 StopIteration 异常, 这并不表示错误发生, 只是告诉外部调用者, 迭代完成.实质上,Python 2.2 序列都是迭代器。Python常见的习惯用法 for elem in lst: 现在实际上让lst产生一个迭代器。然后,for循环反复调用这个迭代器的 .next()方法,
直到它遇到 StopIteration 异常为止。幸运的是,由于所有常见的内置类型自动产生它们的迭代器,所以Python程序员不需要知道这里发生了什么。实际上,现在字典里有 .iterkeys() 、 .iteritems() 和 .itervalues() 方法来产生迭代器;首要的是在新的习惯用法 for key in dct: 中使用了什么。同样,通过调用 .readline() 迭代器支持新的习惯用法 for line in file:迭代器仅是一容器对象,它实现了迭代器协议。它有两个基本方法:
1)next方法返回容器的下一个元素2)__iter__方法返回迭代器自身1、如何创建迭代器
1)iter()函数创建对一个对象调用iter()就可以得到它的迭代器. 它的语法如下:iter(obj)iter(func, sentinel )如果你传递一个参数给 iter() , 它会检查你传递的是不是一个序列, 如果是, 那么很简单:根据索引从 0 一直迭代到序列结束.>>> i = iter('abc')>>> i.next()'a'>>> i.next()'b'>>> i.next()'c'>>> i.next()Traceback (most recent call last): File "<string>", line 1, in <string>StopIteration:2、另一个创建迭代器的方法是使用类一个实现了 __iter__() 和 next() 方法的类可以作为迭代器使用class中__init__()方法执行前述的赋值操作。__iter__()仅返回self,这就是如何将一个对象声明为迭代器的方式,最后,调用next()来得到迭代器中连续的值。next()控制怎么返回下一个值,顺序,倒序,多个步进,随机等。StopIteration异常需要在next抛出。#coding=utf-8class Fib(): def __init__(self, max): self.max = max self.a = 0 self.b = 1 def __iter__(self):return self
def next(self): fib = self.a if fib > self.max: raise StopIteration self.a, self.b = self.b, self.a + self.b return fibfor n in Fib(1000):
print n next倒序的列子class MyIterator(object): def __init__(self, step): self.step = step def next(self): """Returns the next element.""" if self.step==0: raise StopIteration self.step-=1 return self.step def __iter__(self): """Returns the iterator itself.""" return selffor i in MyIterator(4): print inext随机的例子(永不退出)#!/usr/bin/env pythonfrom random import choice
class RandSeq(object):
def __init__(self, seq): self.data = seqdef __iter__(self):
return selfdef next(self):
return choice(self.data)这个例子展示了一些我们可以用定制类迭代器来做的与众不同的事情。一个是无穷迭代。因为我们无损地读取一个序列,所以它是不会越界的。每次用户调用next()时,它会得到下一个迭代值,但我们的对象永远不会引发StopIteration 异常。 八、生成器网上这篇文章比较简洁:http://blog.csdn.net/scelong/article/details/6969276另外一篇很系统的文章:http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html1、什么是生成器,生成器有什么用?当协同程序暂停的时候,我们能从其中获得一个中间的返回值,当调用回到程序中时,能够传入额外或者改变了的参数,但仍能够从我们上次离开的地方继续,并且所有状态完整。挂起返回出中间值并多次继续的协同程序被称为生成器,那就是pytho的生成器真正在做的事。生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。
生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。在Python2.5 提升让生成器更加接近一个完全的协同程序,因为允许值(和异常)能传回到一个继续的函数。
什么是python式的生成器?从句法上讲,生成器是一个带yield 语句的函数。一个函数或者子程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果----那就是yield 语句的功能, 返回一个值给调用者并暂停执行。当生成器的next()方法被调用的时候,它会准确地从离开地方继续(当它返回[一个值以及]控制给调用者时)2、简单的生成器特性
与迭代器相似,生成器以另外的方式来运作:当到达一个真正的返回或者函数结束没有更多的值返回(当调用next()),一个StopIteration 异常就会抛出。这里有个例子,简单的生成器:>>> def simpleGen():... yield 1... yield '2---> punch!'>>> myG=simpleGen()>>> myG.next()#有点怪怪的,函数对象还有方法,next,send,close1>>> myG.next()'2---> punch!'>>> myG.next()Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIterationdef fib(max):
a, b = 0, 1 while a < max: yield a a, b = b, a + b>>> for n in fib(1000): ... print n这个列子比迭代器里的简洁在接下来的例子中,我们将要创建一个带序列并从那个序列中返回一个随机元素的随机迭代器:
>>> from random import randint>>> def randGen(aList):... while len(aList)>0:... yield aList.pop(randint(0,len(aList)-1))#网上例子这里有错误,随机数的范围有问题,没有len(aList)-1不同点在于每个返回的元素将从那个队列中消失,像一个list.pop()和random.choice()的结合的归类。>>> for item in randGen(['rock', 'paper', 'scissors']):... print item... rockscissorspaper使用生成器最好的地方就是当你正迭代穿越一个巨大的数据集合,而重复迭代这个数据集合是一个很麻烦的事,比如一个巨大的磁盘文件,或者一个复杂的数据库查询。对于每行的数据,你希望执行非元素的操作以及处理,但当正指向和迭代过它的时候,你“不想失去你的地盘“2、加强的生成器特性
一些加强特性加入到生成器中,所以除了next()来获得下个生成的值,用户可以将值回送给生成器[send()],在生成器中抛出异常,以及要求生成器退出[close()]由于双向的动作涉及到叫做 send()的代码来向生成器发送值(以及生成器返回的值发送回来),现在yield 语句必须是一个表达式,因为当回到生成器中继续执行的时候,你或许正在接收一个进入的对象。下面是一个展示了这些特性的,简单的例子。我们用简单的闭包例子,counter:>>> def counter(start_at=0):... count = start_at... while True:... val=(yield count) #直接返回初始值 同时将值赋给val... if val is not None: #如yield count返回的不是None 则count=val... count=val... else:#是None的情况 count加1,也就是yield coun没有东西返回的时候count加以... count+=1... 生成器带有一个初始化的值,对每次对生成器[next()]调用以1 累加计数。用户已可以选择重置这个值,如果他们非常想要用新的值来调用send()不是调用next()。这个生成器是永远运行的,所以如果你想要终结它,调用close()方法。如果我们交互的运行这段代码,会得到如下输出:>>> count=counter(5)>>> count.next() #有初始值 返回5>>> count.next() #现在为NONE count6>>> count.send(9)9>>> count.next()10>>> count.close()>>> count.next()Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration>>> count=counter() >>> count.next() #0网上精辟总结:生成器和迭代器
生成器是迭代器,同时也并不仅仅是迭代器,不过迭代器之外的用途实在是不多,所以我们可以大声地说:生成器提供了非常方便的自定义迭代器的途径。