Python命名空间和作用域窥探Word文档格式.docx

上传人:b****3 文档编号:18248358 上传时间:2022-12-14 格式:DOCX 页数:13 大小:78.62KB
下载 相关 举报
Python命名空间和作用域窥探Word文档格式.docx_第1页
第1页 / 共13页
Python命名空间和作用域窥探Word文档格式.docx_第2页
第2页 / 共13页
Python命名空间和作用域窥探Word文档格式.docx_第3页
第3页 / 共13页
Python命名空间和作用域窥探Word文档格式.docx_第4页
第4页 / 共13页
Python命名空间和作用域窥探Word文档格式.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

Python命名空间和作用域窥探Word文档格式.docx

《Python命名空间和作用域窥探Word文档格式.docx》由会员分享,可在线阅读,更多相关《Python命名空间和作用域窥探Word文档格式.docx(13页珍藏版)》请在冰豆网上搜索。

Python命名空间和作用域窥探Word文档格式.docx

, 

abs 

属于直接访问。

两者之间有什么联系呢?

Important

在Python中,scope是由namespace按特定的层级结构组合起来的。

scope一定是namespace,但namespace不一定是scope.

LEGB-rule

在一个Python程序运行中,至少有4个scopes是存在的。

直接访问一个变量可能在这四个namespace中逐一搜索。

∙Local(innermost)

包含局部变量。

比如一个函数/方法内部。

∙Enclosing

包含了非局部(non-local)也非全局(non-global)的变量。

比如两个嵌套函数,内层函数可能搜索外层函数的namespace,但该namespace对内层函数而言既非局部也非全局。

 

∙Global(next-to-last)

当前脚本的最外层。

比如当前模块的全局变量。

∙Built-in(outtermost)

Python 

__builtin__ 

模块。

包含了内建的变量/关键字等。

那么,这么多的作用域,Python是按什么顺序搜索对应作用域的呢?

著名的”LEGB-rule”,即scope的搜索顺序:

Local->

Enclosing->

Global->

Built-in

怎么个意思呢?

当有一个变量在 

local 

域中找不到时,Python会找上一层的作用域,即 

enclosing 

域(该域不一定存在)。

域还找不到的时候,再往上一层,搜索模块内的 

global 

域。

最后,会在 

built-in 

域中搜索。

对于最终没有搜索到时,Python会抛出一个 

NameError 

异常。

作用域可以嵌套。

比如模块导入时。

这也是为什么不推荐使用 

from 

a_module 

import 

的原因,导入的变量可能被当前模块覆盖。

Assignmentrule

看似python作用域到此为止已经很清晰了,让我们再看一段代码:

Python

1

2

3

4

5

6

7

8

9

10

11

defouter():

a=0

b=1

definner():

printa

printb

inner()

outer()

你觉得结果是什么呢?

Soeasy是不是?

cipher<

ahref="

~/Development/Workspace/test_Python$python2a.py

如果多加一句呢?

12

13

14

15

#b+=1 

#A

b=4 

#B

结果又会是什么呢?

Traceback(mostrecentcalllast):

File"

a.py"

line34,in<

module>

line32,inouter

line29,ininner

UnboundLocalError:

localvariable'

b'

referencedbeforeassignment

是不是很奇怪?

原因是这样的:

Python解释器执行到 

inner() 

中的 

print 

时,发现有个变量 

在当前作用域(local)中

无法找到该变量。

它继续尝试把整块代码解释完。

Bingo!

找到了。

那么 

是属于 

作用域的。

既然对变量 

的赋值(声明)发生在 

语句之后, 

语句执行时

变量 

是还未被声明的,于是抛出错误:

变量在赋值前就被引用。

在这个例子中,只有A语句没有B语句也会导致同样的结果。

因为b+=1等同于b=b+1。

对于变量的作用域查找有了了解之后,还有两条很重要的规则:

1.赋值语句通常隐式地会创建一个局部(local)变量,即便该变量名已存在于赋值语句发生的上一层作用域中;

2.如果没有 

关键字声明变量,对一个变量的赋值总是认为该变量存在于最内层(innermost)的作用域中;

也就是说在作用域内有没有发生赋值是不一样的。

但是,在这点上,Python2和Python3又有不同, 

Pythonaccessnon-localvariable:

Python’sscopingrulesindicatethatafunctiondefinesanewscopelevel,

andanameisboundtoavalueinonlyonescopelevel–itisstaticallyscoped.

InPython2.x,itisnotpossibletomodifyanon-localvariable;

1)youhaveeitherread-onlyaccesstoaglobalornon-localvariable,

2)orread-writeaccesstoaglobalvariablebyusingthe 

statement,

3)orread-writeaccesstoalocalvariable(bydefault).

InPython3.x,the 

nonlocal 

statementhasbeenintroducedwithasimilareffect

to 

global,butforanintermediatescope.

for 

循环

为什么讲到作用域要说到 

循环呢?

难道!

@#$%^&

*()?

对于大部分语言(比如 

语言)而言, 

for-loop 

会引入一个新的作用域。

但Python有点一样却又不太一样。

让我们先来看个例子:

16

17

18

19

CipherChen@CIPHERC~/Development/Workspace/test_python$python2

Python2.7.9(default,Jan252015,13:

42:

57)

[GCC4.2.1CompatibleAppleLLVM6.0(clang-600.0.56)]ondarwin

Type"

help"

"

copyright"

credits"

or"

license"

formoreinformation.

>

foriinrange(10):

printi

...

有点不可思议是不是?

在 

Python2.xfor语句 

中是这么说的:

Thefor-loopmakesassignmentstothevariable(s)inthetargetlist.

Thisoverwritesallpreviousassignmentstothosevariableesincludingthosemadeinthesuiteofthefor-loop.

Thetargetlistisnotdeletedwhentheloopisfinished.

Butifthesequenceisempty,theywillnothavebeenassignedtoatalltheloop.

后面跟着的变量(targetlist)在循环结束后是不会被删除的,

但如果 

循环的序列为空,这些变量是完全不会被赋值的。

这在Python中是个大坑啊。

避免这个坑的解决办法就是规范命名规范。

比如用于循环的变量尽量使用单字符。

在任何有疑议的情况可以直接将索引值初始化。

很不幸,Python3中这点没有改变。

ListComprehensionvs.GeneratorExpression

关于Python作用域这堂课已经上了很久了,我们先休息一下,说个题外话吧。

∙列表推导式(ListComprehension)

#Listcomprehension

[expressionforvariniterable]

简单的理解列表推导式:

def_lc(arg):

result=[]

foriinarg:

result.append(i*i)

returnresult

<

expr_value>

=_lc(x)

o列表推导式会把所有数据都加载到内存。

适合“结果需要多次被使用”或者“需要使用list相关的方法(分片等)”等的情况。

∙生成器表达式(GeneratorExpression)

#Generatorexpression

(expressionforvariniterable)

简单的理解生成器表达式:

def_ge(arg):

yieldi*i

&

lt;

expr_value&

gt;

=_ge(x)

o使用生成器实现。

适合“数据量非常大或者无限”的情况。

它们的表现效果分别是这样的:

[iforiinrange(10)]

[0,1,2,3,4,5,6,7,8,9]

(iforiinrange(10))

generatorobject<

genexpr>

at0x7fd5ab625b88>

Python作用域,我已经完全掌握了!

稍作小憩之后,看来大家对Python作用域很有信心了。

好的。

那我们来测试一下。

这是类(class)定义中的一个小问题:

classA(object):

a=3

b=list(a+iforiinrange(10))

这段代码执行起来是不是跟你想的有点一样但又不那么一样呢?

~/Development/Workspace/test_Python$pythona.py

line3,in<

line5,inA

line5,in<

NameError:

globalname'

a'

isnotdefined

刚刚总结的规则完全用不上啊!

“元芳,你怎么看?

真相只有一个:

class没有作用域(scope),但有一个局部的名空间(namespace),它并不构成一个作用域。

这意味着在类定义中的表达式可以访问该名空间。

但在类体(classbody)中,对 

的赋值表达式中,该表达式引入了一个新的作用域,该作用域并不能访问类的名空间。

就像刚刚说的,函数会引入一个新的作用域。

比如说:

classC(object):

a=2

deffoo(self):

returna 

#NameError:

name'

isnotdefined,usereturnself.__class__.a

在Python2中,列表推导式没有引入一个新的作用域。

所以:

[aforainrange(3)]

[0,1,2]

printa

而对于Python2和Python3,生成器表达式都有引入新的作用域。

为了让列表推导式和生成器表达式的表现一致,

在Python3中,列表推导式也有引入一个新的作用域。

Python3.4.2(default,Apr252015,15:

59:

50)

[GCC4.2.1CompatibleAppleLLVM6.0(clang-600.0.57)]ondarwin

print(a)

stdin>

"

line1,in<

解决方案

所以,要解决这个问题,有几种解决办法:

1.用生成器表达式

b=[a+iforiinrange(10)]

1.用函数/lambda引入新的作用域

b=(lambdaa:

((a+iforiinrange(10))))(a)

有没有开始怀疑人生怀疑理想?

附一份:

访问权限汇总表

Canaccessclassattributes

Python2

Python3

listcomp.iterable

Y

listcomp.expression

N

genexpr.iterable

genexpr.expression

dictcomp.iterable

dictcomp.expression

总结

本文介绍了Python中 

namespace 

和 

scope 

的区别,

以及复杂作用域的搜索规则( 

LEGB 

)。

此外,还介绍了一些常见的会创建scope的情况(函数定义,生成器表达式等),当然包括

了Python2和Python3中的不同实现。

Python中对于作用域的定义确实是个大问题,我并没有找到像 

语言那样,

“代码块 

{} 

中定义的即是一个局部作用域”这样简洁的规则来清晰地表明

Python中作用域的 

创建/销毁 

的条件。

这篇文章的内容积压了很久,终于抽了点时间出来整理了下。

写的也有点没章法了,各位看官看得懂就看吧;

看不懂多看几遍吧。

看望之后也提点啥建议意见之类的,好让后来人也能更快速简单的理解这个问题。

万一我理解错了呢?

欢迎探讨。

但有一点可以肯定,“这事儿还没完”。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 中国风

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1