PYTHON函数中的函数(闭包示例)

 

python实例

看概念总是让人摸不着头脑,看几个python小例子就会了

例1

def make_adder(addend):
    def adder(augend):
        return augend + addend
    return adder

p = make_adder(23)
q = make_adder(44)

print p(100)
print q(100)
运行结果:

123
144
分析一下:

我们发现,make_adder是一个函数,包括一个参数addend,比较特殊的地方是这个函数里面又定义了一个新函数,这个新函数里面的一个变量正好是外部make_adder的参数.也就是说,外部传递过来的addend参数已经和adder函数绑定到一起了,形成了一个新函数,我们可以把addend看做新函数的一个配置信息,配置信息不同,函数的功能就不一样了,也就是能得到定制之后的函数.

再看看运行结果,我们发现,虽然p和q都是make_adder生成的,但是因为配置参数不同,后面再执行相同参数的函数后得到了不同的结果.这就是闭包.

例2

def hellocounter (name):
    count=[0]
    def counter():
        count[0]+=1
        print 'Hello,',name,',',str(count[0])+' access!'
    return counter

hello = hellocounter('ma6174')
hello()
hello()
hello() 
执行结果

Hello, ysisl , 1 access!
Hello, ysisl , 2 access!
Hello, ysisl , 3 access!
分析一下

这个程序比较有趣,我们可以把这个程序看做统计一个函数调用次数的函数.count[0]可以看做一个计数器,没执行一次hello函数,count[0]的值就加1。也许你会有疑问:为什么不直接写count而用一个列表?这是python2的一个bug,如果不用列表的话,会报这样一个错误:

UnboundLocalError: local variable 'count' referenced before assignment.

什么意思?就是说conut这个变量你没有定义就直接引用了,我不知道这是个什么东西,程序就崩溃了.于是,再python3里面,引入了一个关键字:nonlocal,这个关键字是干什么的?就是告诉python程序,我的这个count变量是再外部定义的,你去外面找吧.然后python就去外层函数找,然后就找到了count=0这个定义和赋值,程序就能正常执行了.

python3 代码

def hellocounter (name):
    count=0
    def counter():
        nonlocal count
        count+=1
        print 'Hello,',name,',',str(count[0])+' access!'
    return counter

hello = hellocounter('ma6174')
hello()
hello()
hello() 
关于这个问题的研究您可以参考http://linluxiang.iteye.com/blog/789946

例3

def makebold(fn):
    def wrapped():
        return "<b>" + fn() + "</b>"
    return wrapped

def makeitalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

@makebold
@makeitalic
def hello():
    return "hello world"

print hello()
执行结果

<b><i>hello world</i></b>
简单分析

怎么样?这个程序熟悉吗?这不是传说的的装饰器吗?对,这就是装饰器,其实,装饰器就是一种闭包,我们再回想一下装饰器的概念:对函数(参数,返回值等)进行加工处理,生成一个功能增强版的一个函数。再看看闭包的概念,这个增强版的函数不就是我们配置之后的函数吗?区别在于,装饰器的参数是一个函数或类,专门对类或函数进行加工处理。

python里面的好多高级功能,比如装饰器,生成器,列表推到,闭包,匿名函数等,开发中用一下,可能会达到事半功倍的效果!

Python函数中也可以定义函数,也就是闭包。跟js中的闭包概念其实差不多,举个Python中闭包的例子。

def make_adder(addend):
    def adder(augend):
        return augend + addend
    return adder
 
p = make_adder(23)
q = make_adder(44)
 
print(p(100))
print(q(100))
运行结果是:123和144.

为什么?Python中一切皆对象,执行p(100),其中p是make_adder(23)这个对象,也就是addend这个参数是23,你又传入了一个100,也就是augend参数是100,两者相加123并返回。

有没有发现make_adder这个函数,里面定义了一个闭包函数,但是make_adder返回的return却是里面的这个闭包函数名,这就是闭包函数的特征。

再看一个Python闭包的例子:

def hellocounter (name):
    count=[0]
    def counter():
        count[0]+=1
        print('Hello,',name,',',count[0],' access!')
    return counter
 
hello = hellocounter('ma6174')
hello()
hello()
hello()

运行结果:

 

tantengdeMacBook-Pro:learn-python tanteng$ python3 closure.py
Hello, ma6174 , 1  access!
Hello, ma6174 , 2  access!
Hello, ma6174 , 3  access!

使用闭包实现了计数器的功能,这也是闭包的一个特点,返回的值保存在了内存中,所以可以实现计数功能。

时间: 2024-12-30 23:42:28

PYTHON函数中的函数(闭包示例)的相关文章

《Python数据科学指南》——1.12 在函数中嵌入函数

1.12 在函数中嵌入函数 这一节将解释函数式编程里的另一个概念:在一个函数中定义另一个函数. 1.12.1 准备工作 我们写一个简单的函数,它返回输入列表的数值的平方和. 1.12.2 操作方法 我们定义一个简单的函数,用它演示在函数中嵌入函数. # 1.定义一个函数,返回给定输入数值的平方和 def sum_square(x): def square_input(x): return x*x return sum([square_input(x1) for x1 in x]) # 2.输出结

函数调用-怎样在main函数中调用函数

问题描述 怎样在main函数中调用函数 #include <iostream> #include <string> using namespace std; //#define MaxValue 10000; //初始设定的权值最大值 //#define MaxBit 4; //初始设定的最大编码位数 //#define Max 20 //初始设定的最大结点个数 struct HaffNode //哈夫曼树的结点结构 { string data; int weight; //权值

c语言-C语言中函数调用出错问题的解决方法,主函数中的函数参数问题

问题描述 C语言中函数调用出错问题的解决方法,主函数中的函数参数问题 最后的主函数中的Locatei(&Q)一直提示参数不够,但我添加了指向pos的整型变量并赋值给i后仍不能成功,我现在不知道是调用错了还是那里的问题,求解答啊! include include include #define ERROR 0 #define OK 1 #define RL 200 typedef struct{ char *name[RL]; char *phonenum[RL]; char *add[RL];

link中如何定义嵌套的函数,如何在函数中再定义函数呢?

问题描述 link中如何定义嵌套的函数,如何在函数中再定义函数呢? link中如何定义嵌套的函数,如何在函数中再定义函数呢? 解决方案 函数不能嵌套,但可以类似使用 public void Test(){ Fun<intint> add = i => i+1; int i = 5; i = add(i);}

C#通过IronPython调用python脚本中的函数报错 no module named…

问题描述 python脚本中import了第三方的包,单独执行运行脚本没问题,C#通过IronPython调用该脚本则报错:nomodulenamed-(引用的包名),如何解决? 解决方案 解决方案二:将包名如requests2.7中的requests文件夹复制到bin中,不过引用这个包后会出现另外一个报错,求解决解决方案三:现在是只要引用的py文件里有inport,就会报:Microsoft.Scripting.SyntaxErrorException:unexpectedtoken'from

对Python和Go的函数传参研究

传参一直是语言中有点纠结的东西.一提到这个,总会有人说,需要区分传值,传递引用,还有传递指针什么的.而且,貌似不同的语言对此也有不同的实现. 我自己也对这个有点搞混了,所以需要实验一下. 写在开头: 我常用的几个语言是,C++,Go语言,python这几种.三个语言中,只有C++有引用,而Python是没有指针的.参数传递主要就两类,传值和传递引用. 本文只写Python和Go语言,C++太复杂了,需要专门研究. 试验的主要分为几种类型,分别为: 单一的变量类型,比如int,float这种基本类

C++中strcpy函数的实现_C 语言

我们先来看个例子 char * strcpy(char * strDest,const char * strSrc) { if ((NULL==strDest) || (NULL==strSrc)) throw "Invalid argument(s)"; char * strDestCopy = strDest; while ((*strDestCopy++ = *strSrc++) != '\0'); return strDest; } 突然想到之前做过的一个试题 题目:    

C语言中的函数指针基础学习教程_C 语言

顾名思义,函数指针就是函数的指针.它是一个指针,指向一个函数.看例子: A) char * (*fun1)(char * p1,char * p2); B) char * *fun2(char * p1,char * p2); C) char * fun3(char * p1,char * p2); 看看上面三个表达式分别是什么意思? C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型. B) 也很简单,与C)表达式相比,唯一不同的就是函数的

王亟亟的Python学习之路(10)-函数对象的作用域,函数作为返回值,闭包

转载请注明出处:王亟亟的大牛之路 本来打算把工作的事周末做掉点,但是发现在外面浪并不能迅速集中投入,为了避免不必要的BUG 还是明天在家做吧,那么久写一篇Python的文章吧,毕竟背着Mac出门不做些太对不起自己的肩膀了 废话不多,直接说内容,这篇文章的内容大致是围绕"闭包"走的,介绍下相关理论知识 作用域:对象有其存活的范围 闭包:内部函数可以引用外部函数的参数和局部变量(是不是听得云里雾里的,没事 看例子就明白了) 就像循环内声明的对象,除了循环也就无法获取他的值一样.就像在jav