作用域与嵌套函数,默认参数

在python中,当作用域与嵌套函数、默认参数,扯在一起的时候,它们的关系变得复杂,相互关联。下面,将该问题用代码来验证说明,以便理清相互间的关系。

1、在《Python学习手册》第431、432页(下面引为‘书中’),有一段是关于–作用域与带有循环变量的默认参数相比较–,咱们就本着这一段代码来理解这些关系。这两页的内容如下,看客可以先预览一下:
这里写图片描述

2、先在此说明几点:
a)、作用域的搜索规则:LEGB,即local->enclosing->global->built in。
b)、默认参数,实际上已改变了变量的作用域,俗称绑定。此处是重点,也是全文的核心。
c)、任何赋值语句,均会决定变量的作用域,包括import,=,def,类定义等等。

3、如书中第一段代码所示:

>>> def makeActions():
    acts = []
    for i in range(5):
        acts.append(lambda x: i**x)
    return acts

‘i**x’中的i(引为后i)由于在’for i in range(a)’(引为前i)中搜索到,所以作用域上解释是LEGB中的E,也就是lambda函数的上层函数中的i。也就是说,’前i’和’后i’是同个对象名,并且指向相同对象。

如下代码id()可以查看变量的内存地址,代码可以展示’前i’和’后i’的内存关系:

>>> def makeActions():
    acts = []
    for i in range(5):
        print(id(i))
        acts.append(lambda x: (i**x,id(i)))
    return acts

>>> f=makeActions()
1415357504
1415357536
1415357568
1415357600
1415357632
>>> f[0](2)
(16, 1415357632)
>>> f[1](3)
(64, 1415357632)
>>> f[2](2)
(16, 1415357632)

由上述代码可以看出acts[]中所有lambda函数在调用时,i都为4。表明“’前i’和’后i’是同个变量名,指向相同对象”的结论是正确的。
所以在无默认参数情况下,acts[0]中的i=0,acts[1]中的i=1…的想法都是错的。

4、如书中第二段代码所示:

>>> def makeActions():
    acts = []
    for i in range(5):
        acts.append(lambda x,i=i: i**x)
    return acts

此段代码应用了“默认参数”,如本文第2点所述,默认参数实际上就是个赋值语句,已经改变了变量i的作用域。
a)、在”lambda x,i=i:i**x“表达式中第1、3个i是同个i(引为前i),第2个i是另一个i(引为后i)。
b)、由于赋值语句作用,’前i’的作用域实际上是lambda函数的本地变量。而’后i’是’for i in range(5)’中的i。
c)、也就是说,’前i’和’后i’是同个变量名,但是指向不同对象。

下面代码可以展示’前i’和’后i’的内存关系:

>>> def makeActions():
    acts = []
    for i in range(5):
        print(id(i))
        acts.append(lambda x,i=i: (i**x,id(i)))
    return acts

>>> f=makeActions()
1415357504
1415357536
1415357568
1415357600
1415357632
>>> f[0](2)
(0, 1415357504)
>>> f[1](3)
(1, 1415357536)
>>> f[2](2)
(4, 1415357568)

由上述代码可以看出acts[]中所有lambda函数在调用时,i分别指向不同对象。表明“’前i’和’后i’是同个变量名,但指向不同对象”的结论是正确的。
所以在引用默认参数情况下,acts[0]中的i=0,acts[1]中的i=1…的想法都是正确的的。

5、书中第二段代码由于i的作用域问题,让人很容易混乱,若改成下方代码,便一目了然:

>>> def makeActions():
    acts = []
    for i in range(5):
        print(id(i))
        acts.append(lambda x,y=i: (y**x,id(y)))
    return acts

>>> f=makeActions()
1415357504
1415357536
1415357568
1415357600
1415357632
>>> f[0](2)
(0, 1415357504)
>>> f[1](3)
(1, 1415357536)
>>> f[2](2)
(4, 1415357568)

此段代码,不仅从作用域上表明了结果,更加从变量名直观表明,所以,代码还是要清晰,否则逻辑便是混乱的,再牛逼的高手也有写错’the’和’teh’的时候。

注:以上代码,均是在python 3.6.0中运行后摘出。图片摘自python教程,仅供学习参考,如若侵权,请及时联系本人撤销。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值