python基础回顾
演变
先有类,再出现对象,对象生存在内存里;
理论
1、一切都皆为对象,一切皆为对象的引用。
2、只有对名字(变量名-变量)赋值的时候,才会变更引用关系。
变量
1、变量是用一个变量名表示,变量名必须是大小写英文、数字和下划线(_)的组合,且不能用数字开头。
2、变量是在内存中开辟的一个空间,实际表示是name(字符串):name.ref(内存地址)。
3、我们通常将变量名代表变量,变量值代表关联对象。
类
1、类就是类型:object是祖先类型。
2、类型对象是自动生成的,有且仅有一个类型对象实例。1
2
3int、type(1)
>>> type(1) is int
>>> True
对象
1、对象:是类的实例。
2、存活的实例对象都有唯一的id。
3、每个实例对象都持有所属类型的指针。
4、在内存中的标准头,包括引用计数cnt、类型type、其他等。
基础数据(对象)类型:
1、不可变数据(对象)类型:string、tuple、numbers(int、float)
2、可变数据(对象)类型:list、dict
名字空间(namespace)
是从名称到对象的映射。
局部名字空间:从Fast区域按需延迟复制的,静态作用域。
全局名字空间:模块直接用dict实现的,没有使用类似Fast的机制。
1、名字(变量名)、目标对象。
- 将变量(名字)与对象(内存里的)关联起来的容器。
- 名字空间默认使用字典(dict)的数据结构。
2、名字(变量名)的引用必须跟目标对象的引用关联起来。
- 简单理解:变量名(字符串)的引用关联了目标对象的引用。
- 名字空间里实质上是存在{name.ref:obj.ref}的关系。可以通过id(name),看到obj.ref。
3、名字(变量名)关联目标对象的引用关联表就存在于名字空间这个容器。
- 简单理解:变量名(字符串)关联了目标对象的数据结构(字典)
- 名字空间里我们看到的是{name:obj};
- 我们这里只考虑name(字符串):obj(目标对象),不考虑深层次的ref;
4、根据作用域的不同,分为全局名字空间和当前(局部)名字空间。—这里的当前更合适一些,当前是属于局部的;
作用域
Python 程序中可以直接访问一个命名空间的代码区域。
理论
1)根据可变对象和不可变对象;
2)根据只有赋值的时候,才会便能引用关系;
3)同一作用域内,名字总属于单一名字空间,不会因其执行顺序将其引用到不同名字空间。
4)默认形参存储在函数对象的defaults里。
5)内存空间:简单划分Fast(局部变量)和DEREF(外层嵌套,闭包)。
局部作用域里的变量—使用dis.dis模块反汇编查看作用域
1 | T1 = "1" #不可变对象 |
在一个作用域里面给一个变量赋值的时候,Python自动认为这个变量是这个作用域的本地变量,并屏蔽作用域外的同名的变量;
函数的参数
1 | ###############默认形参################## |
函数传入参数:意味着在函数的作用域内 创建了个局部变量,发生引用变更;
函数生成时,形参名字(变量)的引用默认指向函数的defaults属性;
函数被调用时,若传入参数,则形参名字的引用指向新传入的参数,若无,仍指向defaults;
函数每次调用,实际上是在新的局部作用域里,重新生成新的变量;
引用、浅copy、深copy
理论
1)根据可变对象和不可变对象;
2)根据只有赋值的时候,才会便能引用关系;
引用:指向同一个对象
1 | a=5 b=a 就是引用,a、b指向同一个对象; |
浅copy:只复制对象内部的已有的名字引用;
1 | a=["1",2,[1,2,3]] |
深copy
1 | from copy import deepcopy |
闭包
闭包是指函数离开生成环境后,仍可记住并持续引用词法作用域的外部变量。
理论
1)根据可变对象和不可变对象;
2)根据只有赋值的时候,才会便能引用关系;
3)闭包引起的环境变量叫做自由变量,保存在函数对象的closure属性里,从内存的Fast转到DEREF里;
普通的闭包
1 | def func(): |
记住外部状态的闭包
1 | def func(): |
传递函数的闭包
1 |
|
装饰器其实就是利用了闭包的这种方式实现的。
装饰器
原理就是利用闭包在函数里传入一个函数对象,函数对象在闭包里调用。
无参装饰器
1 | def w1(func): |
带参装饰器
1 | def w2(av): |
带参的装饰器,就是又加了一层嵌套