一、闭包概念html
1. 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,而且外函数的返回值是内函数的引用,这样就构成了一个闭包python
2. 通常状况下,在咱们认知当中,若是一个函数结束,函数的内部全部东西都会释放掉,还给内存,局部变量都会消失。算法
3. 可是闭包是一种特殊状况,若是外函数在结束的时候发现有本身的临时变量未来会在内部函数中用到,就把这个临时变量绑定给了内部函数,而后本身再结束。数据结构
二、闭包特色 闭包
1. 必须有一个内嵌函数ide
2. 内嵌函数必须引用外部函数中的变量函数
3. 外部函数的返回值必须是内嵌函数spa
#闭包函数的实例 def outer( a ): b = 10 def inner(): # 在内函数中 用到了外函数的临时变量 print(a+b) # 外函数的返回值是内函数的引用 return inner if __name__ == '__main__': demo = outer(5) demo() # 15 # 在这里咱们调用外函数传入参数5 # 此时外函数两个临时变量 a是5 b是10 ,并建立了内函数,而后把内函数的引用返回存给了demo # 外函数结束的时候发现内部函数将会用到本身的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数 # 咱们调用内部函数,看一看内部函数是否是能使用外部函数的临时变量 # demo存了外函数的返回值,也就是inner函数的引用,这里至关于执行inner函数
三、闭包中内函数修改外函数局部变量 线程
一、在基本的python语法当中,一个函数能够随意读取全局数据,可是要修改全局数据的时候有两种方法:
1) global 声明全局变量
2) 全局变量是可变类型数据的时候能够修改
二、在闭包状况下使用下面两种方法修改
1)在python3中,能够用nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间的变量,须要向上一层变量空间找这个变量。
2)在python2中,没有nonlocal这个关键字,咱们能够把闭包变量改为可变类型数据进行修改,好比列表。指针
#修改闭包变量的实例 def outer( a ): b = 10 # a和b都是闭包变量 c = [a] # 这里对应修改闭包变量的方法2 def inner(): # 方法一: nonlocal关键字声明(python3) nonlocal b b+=1 # 方法二: 把闭包变量修改为可变数据类型 好比列表(python2) c[0] += 1 print(c[0]) print(b) return inner # 外函数的返回值是内函数的引用 if __name__ == '__main__': demo = outer(5) demo() # 6 11
一、预备知识一——python的变量及其存储
1. python的一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只自己
2. 无论多么复杂的数据结构,浅拷贝都只会copy一层。
理解:两我的公用一张桌子,只要桌子不变,桌子上的菜发生了变化两我的是共同感觉的。
>>> str1 = 'hello' >>> str2 = str1 #一、让str1和str2变量都存储了‘hello’所在的内存地址 >>> id(str1) 22748280 >>> id(str1) 22748280 >>> #二、当str1的值变成‘new hello’后str1的值被从新赋值成'new hello'的内存地址,而str2的值依旧是‘hello’的内存地址 >>> str1 = 'new hello' >>> id(str1) 22748320 >>> id(str2) 22748280 #三、无论多么复杂的数据结构,浅拷贝都只会copy一层。 >>> sourceList = [1,2,[3,4]] >>> newList = sourceList >>> l[2][0]=100 >>> sourceList [1, 2, [100, 4]] >>> newList [1, 2, [100, 4]]
二、浅copy与deepcopy
一、浅copy: 无论多么复杂的数据结构,浅拷贝都只会copy一层
二、deepcopy : 深拷贝会彻底复制原变量相关的全部数据,在内存中生成一套彻底同样的内容,咱们对这两个变量中任意一个修改都不会影响其余变量
import copy sourceList = [1,2,3,[4,5,6]] copyList = copy.copy(sourceList) deepcopyList = copy.deepcopy(sourceList) sourceList[3][0]=100 print(sourceList) # [1, 2, 3, [100, 5, 6]] print(copyList) # [1, 2, 3, [100, 5, 6]] print(deepcopyList) # [1, 2, 3, [4, 5, 6]]
垃圾回收机制:http://www.javashuo.com/article/p-fqohqhou-ks.html
一、引用计数
1. 原理
1)当一个对象的引用被建立或者复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1.
2)当对象的引用计数减小为0时,就意味着对象已经再没有被使用了,能够将其内存释放掉。
2. 优势
引用计数有一个很大的优势,即实时性,任何内存,一旦没有指向它的引用,就会被当即回收,而其余的垃圾收集技术必须在某种特殊条件下才能进行无效内存的回收。
3. 缺点
1)引用计数机制所带来的维护引用计数的额外操做与Python运行中所进行的内存分配和释放,引用赋值的次数是成正比的,
2)这显然比其它那些垃圾收集技术所带来的额外操做只是与待回收的内存数量有关的效率要低。
3)同时,由于对象之间相互引用,每一个对象的引用都不会为0,因此这些对象所占用的内存始终都不会被释放掉。
二、标记-清除
1. 说明
1)它分为两个阶段:第一阶段是标记阶段,GC会把全部的活动对象打上标记,第二阶段是把那些没有标记的对象非活动对象进行回收。
2)对象之间经过引用(指针)连在一块儿,构成一个有向图
3)从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。
根对象就是全局变量、调用栈、寄存器。
注:像是PyIntObject、PyStringObject这些不可变对象是不可能产生循环引用的,由于它们内部不可能持有其它对象的引用。
1. 在上图中,能够从程序变量直接访问块1,而且能够间接访问块2和3,程序没法访问块4和5
2. 第一步将标记块1,并记住块2和3以供稍后处理。
3. 第二步将标记块2,第三步将标记块3,但不记得块2,由于它已被标记。
4. 扫描阶段将忽略块1,2和3,由于它们已被标记,但会回收块4和5。
二、缺点
1)标记清除算法做为Python的辅助垃圾收集技术,主要处理的是一些容器对象,好比list、dict、tuple等
由于对于字符串、数值对象是不可能形成循环引用问题。
2)清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描全部对象。
三、分代回收
1. 分代回收是创建在标记清除技术基础之上的,是一种以空间换时间的操做方式。
2. Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代)
3. 他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减少。
4. 新建立的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发
5. 把那些能够被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推
6. 老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。
一、什么是with语句
1. with是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关代码通通去掉,简化try….except….finlally的处理流程。
2. 因此使用with处理的对象必须有enter()和exit()这两个方法
1)with经过enter方法初始化(enter方法在语句体执行以前进入运行)
2)而后在exit中作善后以及处理异常(exit()方法在语句体执行完毕退出后运行)
二、with语句使用场景
1. with 语句适用于对资源进行访问的场合,确保无论使用过程当中是否发生异常都会执行必要的“清理”操做,释放资源
2. 好比文件使用后自动关闭、线程中锁的自动获取和释放等。
三、with处理文件操做的实例
with open('/etc/passwd') as f: for line in f: print(line)
# 这段代码的做用:打开一个文件,若是一切正常,把文件对象赋值给f,而后用迭代器遍历文件中每一行,当完成时,关闭文件;
# 而不管在这段代码的任何地方,若是发生异常,此时文件仍会被关闭。