2.1.1 印象
我们习惯将生物分为动物,植物,进而又有猫科,犬科等细分,通过对个体的研究,归纳其共同特征,抽象成便于描述的种族模版,有了模版后,可据此创建大量行为类似的个体,所以,分类是个基础工程。
在专业术语上,我们将族群或类别乘坐类型(class),将个体叫做实例(instance)。类型持有同族个体的共同行为和共享状态,而实例仅保存私有特性即可。如此,在内存空间布局上才是最高效的。
每个实例都持有所属类型的指针。需要时,通过它间接访问目标即可。但从外在逻辑接口看,任何实例都是“完整”的
存活实例对象都有“唯一”id值:
补充:
id()函数:用于获取对象的内存地址
语法:id([object])
返回值:返回对象的内存地址。
可用type返回实例所属的类型:
要判断实例是否属于特定类型,可以使用isinstance函数
补充:
isinstance()函数:判断一个对象是否是一个已知类型
语法:isinstance(object, classinfo)
参数:
object -- 实例对象。
classinfo -- 可以是直接或间接类名、基本类型或者由它们组成的元组。
返回值:如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()
任何类型都是其祖先类型的子类,同样,对象也可以被判定为其祖先类型的实例
class A: pass class B(A): pass print(issubclass(B,A))
结果:
补充:
issubclass():用于判断参数class是否是类型参数classinfo的子类
语法:issubclass(class, classinfo)
参数:
class -- 类
classinfo -- 类
返回值:如果 class 是 classinfo 的子类返回 True,否则返回 False
注意:所有类型都有一个共同的祖先类型object,它为所有类型提供原始模版,以及系统所需的基本操作方式
class A: pass class B(A): pass print(issubclass(B,object))
结果:
类型虽然是抽象族群概念,但在实现上也只是个普通的对象实例,区别在于,所有类型都是由type创建,这和继承没有关系
单就类型对象而言,其本质就是用存储方法和字段成员的特殊容器,用同一份涉及来实现才是正常思路,当然,类型对象属于创建者这样的特殊存在,默认情况下,它们由解释器在首次载入时自动生成,生命周期与进程相同,且仅有一个实例
2.1.2 名字
在通常认知里,变量是一段具有特定格式的内存,变量名则是内存别名,因为在编码截断,无法确定内存的具体位置,故使用名称符号代替
静态编译和动态解释型语言对于变量名字处理方式的不同点:
静态编译:静态编译器或链接器会以固定地址,或直接、间接寻址指令代替变量名,也就是说,变量名不参与执行过程,可被剔除。
动态解释型语言:名字和变量通常是两个运行期实体。名字不但有自己的类型,还需要分配内存,并介入执行过程。甚至可以说,名字才是动态模型的基础
名字必须要与目标对象关联起来才有意义,最直接的关联操作就是负值,而后对名字的引用都被解释为对目标对象进行操作
赋值步骤:
1.准备好右值目标对象
2.准备好名字
3.在名字空间里为两者建立关联(namespace{名字:目标对象})
即便如此,名字与目标对象也仅是引用关联,名字只负责招人,但对此人一无所知。鉴于在运行期才能知道名字引用的目标类型,所以说Python是一种动态类型语言
名字空间:
名字空间(namespace):是专门用来存储名字和目标引用关联的容器
对Python而言,每个模块(源码文件)都有一个全局名字空间。而根据代码作用域,又有当前名字控件或本地名字空间一说,如果直接在模块级别执行,那么当前名字空间和全局名字空间相同,但在函数内,当前名字空间就专指函数作用域
名字空间默认使用字典数据结构,由多个键值对组成
内置函数globals和locals分别返回全局名字空间和本地名字空间字典
代码1:
y=100 print(id(globals())) print(id(locals())) print(globals()) print(locals())
结果1:
30466768 30466768 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000000003A1CC0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Pyexerice/func_lambda1.py', '__cached__': None, 'y': 100} {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000000003A1CC0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Pyexerice/func_lambda1.py', '__cached__': None, 'y': 100}
此时globals和locals指向相同,所以内存地址相同,结果相同
代码2:
def test(): y = 100 print(id(globals())) print(id(locals())) print(globals()) print(locals()) test()
结果2:
30663376 39180904 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000001CF1CC0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Pyexerice/func_lambda1.py', '__cached__': None, 'test': <function test at 0x0000000001D2C1E0>} {'y': 100}
可以看到,此时globals和locals的内存地址不同,由此可见,globals总是指向模块名字空间,而locals则是指向当前作用域环境
未完待续