通过5个知识点轻松搞定Python的作用域

来源:本网整理

count = 0 def onOpen(self): #文件导入 path = QtGui.QFileDialog.getOpenFileName(self, 'Open file','./') file = open(path) data = file.read() self.newItem = QtGui.QTableWidgetItem(file.name) self.table.setItem(0,count,self.newIte

s">

通过5个知识点轻松搞定Python的作用域

投稿:daisy 字体:[增加 减小] 类型:转载 时间:2016-09-09 我要评论 网上关于python的作用域介绍有很多,那么小编今天给大家分享的这篇文章是让大家通过学习这5个知识点,可以轻松搞定Python的作用域,有需要的朋友们可以参考借鉴。 ">

1、块级作用域

简单说,闭包就是根据不同的配置信息得到不同的结果 再来看看专业的解释:闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,

想想此时运行下面的程序会有输出吗?执行会成功吗?

golbal s 指定当前作用域里面的s是全局的,不影响其他的作用域

#块级作用域 if 1 == 1: name = "lzl" print(name) for i in range(10): age = i print(age)

这篇文章主要介绍了Python函数式编程指南(一):函数式编程概述,本文讲解了什么是函数式编程概述、什么是函数式编程、为什么使用函数式编程、如何辨认函数式风格等核心知识,需要的朋友可以参考下 1pareTo(o2)) 相信从这个小小的例子你也能感受到

我们先看下执行结果

C:/Users/L/PycharmProjects/s14/preview/Day8/作用域/main.py lzl 9 Process finished with exit code 0

教狗狗上厕所一定要从小教起,一般3-4个月的小狗最好教,许多宠友喜欢把狗狗关在厕所里,这样它更加不会拉屎尿尿,因为它会觉得厕所是它的窝,谁会在自己的窝里撒尿呢?下面提供几个教狗狗上厕所的方法供参考:1、在狗狗第一天到家里时,可用手纸或报纸在它的屁屁上多擦几下,然后置于厕所里一个固定点,再让它多嗅几下,确定以后拉尿位置。2、使用宠物诱便液,在厕所垫上报纸,再洒上宠物诱便液,然后还是要让它在报纸上多嗅嗅。或者把第一个方法做完之后再加上第二个方法。3、它在家里四处乱拉,这时可用报纸垫在它拉过尿的地方浸上它的尿液,再放入厕所,然后再重复的让它去嗅,把家里有尿的位置用消洗灵或去味剂洗干净。狗狗一般很顽皮

代码执行成功,没有问题;在Java/C#中,执行上面的代码会提示name,age没有定义,而在Python中可以执行成功,这是因为在Python中是没有块级作用域的,代码块里的变量,外部可以调用,所以可运行成功;  

谢邀!一般来说,一个男人想跟一个女人生孩子,说明他是打算跟这个女人好下去的。但也不排除这个男人并不懂得生过孩子,生活带来的改变。他会不会因此负责任地对待女人以及孩子,也不能仅仅凭借想跟你生孩子这一主观意愿来判断。或者,他只想跟你生,却还没确定跟你结婚呢?一个男人爱不爱你,你应该在相处过程中去感受,从细节中感受,从吵架生气时感受,从病痛困难中感受,从对待你的亲人朋友的表现中感受……相信你心里会有一杆秤。

 2、局部作用域

宝宝镇楼图我是一个80后的宝妈,两胎都是剖腹产的,一儿一女圆满了,生二胎的意义或许就在于:带你们一起来到这陌生的世界,一路相伴相随,共同成长,当有一天我们老去的时候,你们还能庆幸有一个血浓于水的手足,这就够了。老大是由于过预产期几天不发动,每次胎监都吸氧做还不一定过关,就稀里糊涂的剖了。剖了没啥感觉就下手术台,孩子也出来了。以为第二胎应该更有经验,更没啥事,结果完全想错了。术前准备都很轻松,还和医护人员开玩笑,跟麻醉师说一定要告诉我生的是儿子!等麻醉一上来手术快开始就紧张了,脑袋里不断浮现出之前看过的剖腹产过程视频!医生开始手术了,切开腹腔没有疼痛感,可是等腹腔一切来弄里面就开始有痛感了,问麻

回顾之前学过的知识,我们学函数的时候,函数是个单独的作用域,Python中没有块级作用域,但是有局部作用域;看看下面的代码

玩过单反一定知道,我们所说的光圈大小是用“f/数值”来表示的,“f/”后面的数值越小,代表其光圈越大,数值越大,代表其光圈越小。如f/4的光圈就要比f/8的光圈大。这个光圈F值有一个计算公式:光圈F值=镜头的焦距/镜头光圈的直径,即使数学考七分你也能发现,这些光圈值是以1.4倍的关系变化的。原来,光圈开大一级,要求通过光的面积增加一倍,因为圆形的面积与直径的平方值成正比,也就是说光圈面积就与光圈直径的平方成正比,所以光圈直径就需要增加根号2倍=1.4倍啦~在其它设置不变的情况下,光圈越大图像就会越亮,因为光圈越大,单位时间内的曝光量就越多,图像自然就会越亮,反之亦然。实际拍摄中你可能也听过有个

#局部作用域 def func(): name = "lzl" print(name)

运行这段代码,想想会不会有输出?

Traceback (most recent call last): File "C:/Users/L/PycharmProjects/s14/preview/Day8/作用域/main.py", line 23, in <module> print(name) NameError: name 'name' is not defined

运行报错,我相信这个大家都能理解,name变量只在func()函数内部中生效,所以在全局中是没法调用的;对上面代码做个简单调整,再看看结果如何?

#局部作用域 def func(): name = "lzl" func() #执行函数 print(name)

对之前的代码添加了一句代码,在变量name打印之前,执行了一下函数,此时打印会不会有变化?

Traceback (most recent call last): File "C:/Users/L/PycharmProjects/s14/preview/Day8/作用域/main.py", line 23, in <module> print(name) NameError: name 'name' is not defined

执行依然报错,还是回到刚才那句话:即使执行了一下函数,name的作用域也只是在函数内部,外部依然无法进行调用;把前两个知识点记住,接下来要开始放大招了

3、作用域链

对函数做下调整,看看下面的代码执行结果如何?

#作用域链 name = "lzl" def f1(): name = "Eric" def f2(): name = "Snor" print(name) f2() f1()

学过函数,肯定知道最后f1()执行完会输出Snor;我们先记住一个概念,Python中有作用域链,变量会由内到外找,先去自己作用域去找,自己没有再去上级去找,直到找不到报错

4、终极版作用域

好,铺垫了够了,终极版的来了~~

#终极版作用域 name = "lzl" def f1(): print(name) def f2(): name = "eric" f1() f2()

想想最后f2()执行结果是打印“lzl”呢,还是打印“eric”?记住自己的答案,现在先不把答案贴出来,先看看下面这段代码:

#终极版作用域 name = "lzl" def f1(): print(name) def f2(): name = "eric" return f1 ret = f2() ret() #输出:lzl

执行结果为“lzl”,分析下上面的代码,f2()执行结果为函数f1的内存地址,即ret=f1;执行ret()等同于执行f1() ,执行f1()时与f2()没有任何关系,name=“lzl”f1()在一个作用域链,函数内部没有变量是会向外找,所以此时变量name值为“lzl”;理解了这个,那么刚才没给出答案的那个终极代码你也知道答案了

#终极版作用域 name = "lzl" def f1(): print(name) def f2(): name = "eric" f1() f2() # 输出:lzl

是的,输出的是“lzl”,记住在函数未执行之前,作用域已经形成了,作用域链也生成了

5、新浪面试题

li = [lambda :x for x in range(10)]

判断下li的类型?li里面的元素为什么类型?

print(type(li)) print(type(li[0])) # <class 'list'> # <class 'function'>

可以看到li为列表类型,list里面的元素为函数,那么打印list里面第一个元素的返回值,此时返回值为多少?

#lambada 面试题 li = [lambda :x for x in range(10)] res = li[0]() print(res) #输出:9

li第一个函数的返回值为9还不是0,记住:函数在没有执行前,内部代码不执行;博客里面的代码可以自己练练,加深下印象

总结

以上就是这篇文章的全部内容了,不知道对大家的学习和工作能不能带来一些帮助,如果大家有疑问可以留言交流。

扩展阅读,根据您访问的内容系统为您准备了以下内容,希望对您有帮助。

PYTHON 的变量作用域与内存分配

原理:python中任何变量都是对象,所以参数只支持引用传递方式。即通过名字绑定的机制,把实际参数的值和形式参数的名称绑定在一起,形式参数和实际参数指向内存中的同一个存储空间。

回答问题2:

每一次给变量赋值就是把这个名称的值在一个新内存中存储 你print (id (a)) 会发现每一次f(x),a的内存地址都是新的。所以你的问题二中L=[4,3] 与之前的L[]不是同一个名称,所以append上a就是[4,3,3](简明点就是L=[4,3]与L=[1,2]是两不同名的玩意)

讨论问题1:

在你的程序中a=1,a=2,a=5是int对象的三个实例,所以占用的是三段不同的内存,自然在程序执行完收回内存的时候才会被清理;而L是通过列表的append方法进行变化时,print (f(1))

print (f(2)) print (f(5))是对对一个实例进行操作的,所以内存地址不变; 同理print (f(3,[4,3]))直接给L赋值时,由于 是一个新的列表实例了,内存位置自然变化。

产生以上的问题的根本原因就是python的精髓:万物皆对象 (赋值的过程是对象的实例化)

看完自己的回答后:感觉真的很绕,不过我是尽力了,希望你能看懂,不明白的话,在追问里注明吧!追问十分感谢,但是我还有些问题。

如果a和L是在main的生命周期结束后才销毁,那在main中重复调用f(),f(1,[1]),f(2,[2]),f(3,[3]).....这样搞个几万次,那每次都会有新的实例生成并且只在程序结束时回收?这样不是会造成泄漏?是否需要在f()函数最后del(a)呢?

还有,我那段代码起初是在python3x上跑的,4次ID的地址一样,所以我很奇怪。

今天拿到2x上跑,第三次就不一样了,这样还比较好理解。第三次肯定是申请了新内存。追答好吧,承认这个问题问的很好,我也受教了。以下是我查到的资料。应该可以解决你的疑惑了。呵呵

小块空间的内存池

  在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。

 Python内存池全景

  这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。这也就是之前提到的Pymalloc机制。

  在Python 2.5中,Python内部默认的小块内存与大块内存的分界点定在256个字节,这个分界点由前面我们看到的名为SMALL_REQUEST_THRESHOLD的符号控制。

  也就是说,当申请的内存小于256字节时,PyObject_Malloc会在内存池中申请内存;当申请的内存大于256字节时,PyObject_Malloc的行为将蜕化为malloc的行为。当然,通过修改Python源代码,我们可以改变这个默认值,从而改变Python的默认内存管理行为。

  在一个对象的引用计数减为0时,与该对象对应的析构函数就会被调用。

  Python内存管理规则:del的时候,把list的元素释放掉,把管理元素的大对象回收到py对象缓冲池里。

---------------

以上不是完整的,字数受限,详细请看

http://www.techweb.com.cn/tech/2010-07-23/647118.shtml

python中实例属性和类属性之间的关系

一般来说,在Python中,类实例属性的访问规则算是比较直观的。

但是,仍然存在一些不是很直观的地方,特别是对C++和Java程序员来说,更是如此。

在这里,我们需要明白以下几个地方:

1.Python是一门动态语言,任何实体都可以动态地添加或删除属性。

2.一个类定义了一个作用域。

3.类实例也引入了一个作用域,这与相应类定义的作用域不同。

4.在类实例中查找属性的时候,首先在实例自己的作用域中查找,如果没有找到,则再在类定义的作用域中查找。

5.在对类实例属性进行赋值的时候,实际上会在类实例定义的作用域中添加一个属性(如果还不存在的话),并不会影响到相应类中定义的同名属性。

下面看一个例子,加深对上述几点的理解:

复制代码

代码如下:

class A:

cls_i = 0

cls_j

= {}

def __init__(self):

self.instance_i =

0

self.instance_j =

{}

在这里,我们先定义类A的一个实例a,然后再看看类A的作用域和实例a的作用域中分别有什么:

复制代码

代码如下:

>>> a = A()

>>>

a.__dict__

{'instance_j': {}, 'instance_i': 0}

>>>

A.__dict__

{'__init__': , '__module__': '__main__', 'cls_i': 0, 'cls_j': {},

'__doc__': None}

我们看到,a的作用域中有instance_i和instance_j,A的作用域中有cls_i和cls_j。

我们再来看看名字查找是如何发生的:

复制代码

代码如下:

>>> a.cls_i

0

>>>

a.instance_i

0

在查找cls_i的时候,实例a的作用域中是没有它的,却在A的作用域中找到了它;在查找instance_i的时候,直接可在a的作用域中找到它。

如果我们企图通过实例a来修改cls_i的值,那会怎样呢:

复制代码

代码如下:

>>> a.cls_i = 1

>>>

a.__dict__

{'instance_j': {}, 'cls_i': 1, 'instance_i': 0}

>>>

A.__dict__

{'__init__': , '__module__': '__main__', 'cls_i': 0, 'cls_j': {},

'__doc__': None}

我们可以看到,a的作用域中多了一个cls_i属性,其值为1;同时,我们也注意到A作用域中的cls_i属性的值仍然为0;在这里,我们其实是增加了一个实例属性,并没有修改到类属性。

如果我们通过实例a操纵cls_j中的数据(注意不是cls_j本身),又会怎么样呢:

复制代码

代码如下:

>>> a.cls_j['a'] =

'a'

>>> a.__dict__

{'instance_j': {}, 'cls_i': 1, 'instance_i':

0}

>>> A.__dict__

{'__init__': , '__module__': '__main__',

'cls_i': 0, 'cls_j': {'a': 'a'}, '__doc__': None}

我们可以看到a的作用域没有发生什么变化,但是A的作用域发生了一些变化,cls_j中的数据发生了变化。

实例的作用域发生变化,并不会影响到该类的其它实例,但是类的作用域发生变化,则会影响到该类的所有实例,包括在这之前创建的实例:

复制代码

代码如下:

>>> A.cls_k = 0

python 函数作用域问题,

类在定义的时候是有作用域的,这个作用域内的变量只能在 class 块内访问,而不能在类的方法(函数)中访问。

python for循环作用域问题

你append(alien),意味着,你的aliens 里面装了20个 alien,并且这20个alien都是内存地址是一样的,也就是20个人共用一桶水,其中一个人把里面的水换成了啤酒,大家喝的只能是啤酒.

解决办法:

for aliens_number in range(20):

a=alien.copy()

aliens.append(a)

python中什么叫局部作用域

1.这个怎么看,我不能理解;2.全局变量局部变量有什么区别吗? 区别肯定有的,不然名字就没必要区分了。全局的作用域比较大,一般在程序代码中任何地方都可以调用,局部变量一般只在函数内部使用。3.函数,说白了就是实现不同功能的代码段,比如MAX(a,b,c,...)函数,求最大值, MIN(a,b,c,...)函数,求最小值等、、、、还有很多。函数一般只知道使用方法(比如所需参数,返回值)和实现功能就行。

  • 本文相关:
  • Python冒泡排序注意要点实例详解
  • Python 中的with关键字使用详解
  • Python优化技巧之利用ctypes提高执行速度
  • Python 如何访问外围作用域中的变量
  • Python中使用asyncio 封装文件读写
  • asyncio 的 coroutine对象 与 Future对象使用指南
  • 基于asyncio 异步协程框架实现收集B站直播弹幕
  • python开发环境PyScripter中文乱码问题解决方案
  • Python读取图片属性信息的实现方法
  • 全面了解python中的类,对象,方法,属性
  • 免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved