变量赋值

  1. a = 5 #相当于void *a = &Number(5),创建了一个Number(5)对象
  2. #第一次给a赋值,创建变量a
  3. #不需要声明a的数据类型,python眼中,所有的变量都是void*指针,类型说的是指向的对象。
  4. a = 10 #第二次赋值,就是普通意义的赋值
  5. #相当于a = &Number(10),创建了Number(10)对象
  6. #最终的效果就是a指向了一个全新的对象。
  7. a = [1,2,3] #变量可以指向任意类型的对象,void*嘛。
  8. #对象是[1,2,3]是List类型
  9. del a #删除变量a对对象的引用,a不再指向任何对象,a不可再使用。
  10. a = b = c = 1 #多变量赋值
  11. a, b, c = 1, 2, "john" #多变量赋值,类似lua

变量作用域

全局作用域:在函数体外定义的变量,程序范围内可访问。
局部作用域:在函数体内定义的变量,只在函数体内可访问。

类似C++的全局变量,局部变量。

名字查找规则和C++类似,优先查找当前所在最小范围作用域,比如函数体内,优先查找函数内的局部作用域,如果没找到,再从全局作用域找。

  1. var = 1; #定义了一个全局变量
  2. def fuck():
  3. var = 2; #定义了一个局部变量,
  4. #在局部作用中,覆盖了全局变量var的名字,通过var只会查找到局部变量。
  5. global var #显式声明使用全局变量var,接下来的var指的全部是全局变量。
  6. var = 2; #全局变量var的值改为1。
  7. nonlocal var #显式声明使用外层作用域的变量var,不包括全局作用域
  8. #这里是错误的,因为外层作用域已经是全局作用域。
  9. def shit():
  10. nonlocal var #正确,使用fuck函数作用域的var变量。
  11. pass

globals()、locals()内置函数
globals(),返回当前作用域内可访问的全局名字。
locals(),返回当前作用域内的名字。

  1. gvar = 1
  2. def fuck():
  3. lvar = 1
  4. print(globals()) # {"gvar":1}
  5. print(locals()) # {"lvar":1}
  6. print(globals()) # {"gvar":1}
  7. print(locals()) # {}

对象生命周期

python和lua一样,垃圾自动回收。
使用引用计数来跟踪回收垃圾。
引用计数器记录着每个对象的当前引用数量,数量=0时,它将被垃圾回收,回收不是”立即”的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。
原理类似于C++的智能指针shared_ptr。

  1. a = 40 # 创建对象<40>,对象<40>引用计数=1
  2. b = a # 对象<40>引用计数+1,因为变量b也引用了对象
  3. c = [b] # 对象<40>引用计数+1
  4. del a # 对象<40>引用计数-1,解除了a对对象<40>的引用
  5. b = 100 # 对象<40>引用计数-1,对象<100>引用计数=1
  6. c[0] = -1 # 对象<40>引用计数-1,对象<40>引用计数=0,下一轮垃圾回收,对象将被回收。