python 原理理解笔记

变量实际上是一个字符串的符号,用来关联一个存储在内存中的对象。在 Python 中,会使用 dict(就是 Python 的 dict 对象)来存储变量符号(字符串)与一个对象的映射。

那么赋值语句实际上就是用来建立这种关联,在这个例子中是将符号 a 与一个列表对象 [1, ‘python’] 建立映射。

也就是说python维持这样一个字典,每定义一个变量就等于往字典里插入新的键值对。每次重新赋值就是更新对应的键值对。

在高级语言中,变量是对内存及其地址的抽象。对于python而言,python的一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。

然而有的时候,我们偏偏需要将一份数据的原始内容保留一份,再去处理数据,这个时候使用赋值就不够明智了。python为这种需求提供了copy模块。提供了两种主要的copy方法,一种是普通的copy,另一种是deepcopy。我们称前者是浅拷贝,后者为深拷贝。

 首先,我们来了解一下浅拷贝。浅拷贝:不管多么复杂的数据结构,浅拷贝都只会copy一层。
 
 我们引入一个深拷贝的概念,深拷贝——即python的copy模块提供的另一个deepcopy方法。深拷贝会完全复制原变量相关的所有数据,在内存中生成一套完全一样的内容,在这个过程中我们对这两个变量中的一个进行任意修改都不会影响其他变量。
 
 

我们的 Python 代码继续往下运行,这里执行到一条 def func(),从字节码指令中也可以看出端倪 MAKE_FUNCTION。没错这条指令是用来创建函数的。Python 是动态语言,def 实际上是执行一条指令,用来创建函数(class 则是创建类的指令),而不仅仅是个语法关键字。函数并不是事先创建好的,而是执行到的时候才创建的。
def func() 将会创建一个名称为 func 的函数对象。实际上是先创建一个函数对象,然后将 func 这个名称符号绑定到这个函数上。

Python 中是无法实现 C 和 Java 中的重载的,因为重载要求函数名要相同,而参数的类型或数量不同,但是 Python 是通过变量符号(如这里的 func)来关联一个函数,当我们用 def 语句再次创建一个同名的函数时,这个变量名就绑定到新的函数对象上了。

动态类型

继续看函数 func 里面的代码,这时又有一条赋值语句 a = 1。变量 a 现在已经变成了第三种类型,它现在是一个整数了。那么 Python 是怎么实现动态类型的呢?答案就藏在具体存储的对象上。变量 a 仅仅只是一个符号(实际上是一个字符串对象),类型信息是存储在对象上的。在 Python 中,对象机制的核心是类型信息和引用计数(引用计数属于垃圾回收的部分)。

因为 a 和 b 并不存储类型信息,因此当执行 a + b 的时候就必须先检查类型,比如 1 + 2 和 “1” + “2” 的结果是不一样的。
看到这里,我们就可以想象一下执行一句简单的 a + b,Python 虚拟机需要做多少繁琐的事情了。首先需要分别检查 a 和 b 所对应对象的类型,还要匹配类型是否一致(1 + “2” 将会出现异常),然后根据对象的类型调用正确的 + 函数(例如数值的 + 或字符串的 +),

也就是说对象本身存储了类型信息所以在使用变量名执行相关操作的时候先通过变量名找到对应的对象判断是啥类型再看是否匹配相应的操作,再执行相应的操作。

命名空间

在 Python 中,类、函数、module 都对应着一个独立的命名空间。而一个独立的命名空间会对应一个 PyCodeObject 对象
命名空间的意义,就是用来确定一个变量符号到底对应什么对象。命名空间可以一个套一个地形成一条命名空间链,Python 虚拟机在执行的过程中,会有很大一部分时间消耗在从这条命名空间链中确定一个符号所对应的对象是什么。

在 Python中,命名空间是由一个 dict 对象实现的,它维护了(name,obj)这样的关联关系。
当python中的某段代码要访问一个变量x时,python会在所有的命名空间中寻找这个变量,查找的顺序为:
- local namespace - 指的是当前函数或者当前类方法。如果在当前函数中找到了变量,停止搜索
- global namespace - 指的是当前的模块。如果在当前模块中找到了变量,停止搜索
- build-in namespace - 如果在之前两个namespace中都找不到变量x,python会假设x是build-in的函数或者变量。如果x不是内置函数或者变量,python会报错NameError。

对于闭包来说,这里有一点区别,如果在local namespace中找不到变量的话,还会去父函数的local namespace中找变量。

  • 内置函数locals(), 返回当前函数(方法)的局部命名空间
  • 内置函数globals(),返回当前module的命名空间
  • locals()和globals()有一个区别是,locals只读,globals可以写

python中的module也是对象,所有的modules都有一个内置的属性name,模块的name属性的值取决于如何使用这个模块,如果import module,那么name属性的值是模块的名字。如果直接执行这个模块的话,那么name属性的值就是默认值main

猜你喜欢

转载自blog.csdn.net/zhc_24/article/details/82119541