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


本来打算把工作的事周末做掉点,但是发现在外面浪并不能迅速集中投入,为了避免不必要的BUG 还是明天在家做吧,那么久写一篇Python的文章吧,毕竟背着Mac出门不做些太对不起自己的肩膀了


废话不多,直接说内容,这篇文章的内容大致是围绕“闭包”走的,介绍下相关理论知识

作用域:对象有其存活的范围
闭包:内部函数可以引用外部函数的参数和局部变量(是不是听得云里雾里的,没事 看例子就明白了)

就像循环内声明的对象,除了循环也就无法获取他的值一样。就像在java中声明的静态变量它的作用域就在整个类都有效一样。

那如果在非对象可存活的范围内操作了某个对象编译器也不会让我们通过的,像这样(拿一个错误的闭包函数来演示下)

这里写图片描述

那再上一个对的实现

这里写图片描述

也就引出了“高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回”。

我们来解释下这2个例子,首先外层有一个wdd函数,它里面有一个line函数因为我们图1他超出了合理的作用域所以编译器就报错了。

那我们再来分析下第二个例子,我们也是外面有一个wdd()函数,里面有一个line函数 函数返回值为 传入的参数x*2+50 然后line()函数的计算结果作为wdd()函数的返回值

这也就是我们所说的 函数作为返回值,实质上其实就是类似于 我们声明了一个 k 然后wdd()这个函数赋值给了k 然后line(x) 这个函数引用了外部函数的参数 5 然后计算出结果后的结果返回给了外部函数wdd。

那有些人问了 直接

print(wdd(5))

不行吗?

我们再贴个例子来看一下

def sumLogic2(*args):
    def addAll():
        sumValue2 = 0
        for k in args:
            sumValue2 = sumValue2 + k
        return sumValue2

    return addAll

这个例子跟wdd区别只是计算的算法不同,结果完全相同,主要看下不同的调用的结果

result = sumLogic2(1, 2, 3, 4, 5)
print(result())
print(sumLogic2(1, 2, 3, 4, 5))

结果:
15
.addAll at 0x101b7b840>

这也就验证了我们刚才说的 我们 sumLogic2(1, 2, 3, 4, 5) 其实返回的是addAll()方法,调用函数result时,才真正计算结果。

再顺道上一下证明 内部函数可以引用外部函数的参数和局部变量 的例子

def wjj(z, x, c):
    a = 20

    def wjj2():
        return a*(z * x * c)

    return wjj2


k = wjj(2, 3, 4)
print(k())

结果:
480

这个例子不仅引用了局部变量,也使用了外部传入wjj方法的参数。

那我们每次调用同一个外部函数返回的是同一个对象吗?

拿刚才的result验证下

def sumLogic2(*args):
    def addAll():
        sumValue2 = 0
        for k in args:
            sumValue2 = sumValue2 + k
        return sumValue2

    return addAll


result = sumLogic2(1, 2, 3, 4, 5)
print(result())
print(sumLogic2(1, 2, 3, 4, 5))

result2 = sumLogic2(1, 2, 3, 4, 5)

print(result == result2)

结果:
15
.addAll at 0x101b7b840>
False

那也就说明调用结果互不影响。

是不是对大致的使用 有了点概念?

什么? 还不清楚,还是觉得闭包没用? 那么看以下例子

def line_conf(a, b):
    def line(x):
        return a*x + b
    return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5), line2(5))

结果:

6 25

这个例子中,函数line与环境变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个环境变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。

如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。利用闭包,我们实际上创建了泛函。line函数定义一种广泛意义的函数。这个函数的一些方面已经确定(必须是直线),但另一些方面(比如a和b参数待定)。随后,我们根据line_conf传递来的参数,通过闭包的形式,将最终函数确定下来。

是不是发现瞬间觉得有那么点用了?


现在手头运作一些公司的职位,有兴趣的小伙伴可以U 简历到[email protected]

公司:Pactera 地点:上海 职位: Java PHP Android UI设计 .Net 服务于平安好车项目(大企业,大项目)

公司:阿里巴巴 地点 :上海,杭州,北京 职位: Android/iOS 淘宝/蚂蚁/其他子公司(有一定能力,学历要求)

公司:暴走漫画 地点:上海 职位:Android/iOS 暴走大事件配套App产品(大用户量产品)

评论关闭