阅读 79

[Python 我想] 2. 对象与变量

知识点

本来的题目是可变变量和不可变变量,但是越写越觉得不对,改为了对象与变量。

本文中的内容对应的是 interview_python 的第一项内容:Python 的函数参数传递。原文中举得两个例子:

a = 1
def fun(a):
    a = 2
fun(a)
print a  #输出 1
复制代码
a = []
def fun(a):
    a.append(1)
fun(a)
print a #输出 2
复制代码

后面指出所有的变量都可以理解为内存中一个对象的“引用”,理解为 C 语言中指针的概念。 其实按照我自己的理解,第一段代码对应的一个知识点是作用域(维基百科)。函数 fun 的作用域中 a 不会影响到函数外打印出来的 a。我想后面提供的这段代码能够更好的展现他想讲述的内容。

a = 1
def fun(a):
    print "func_in",id(a)   # func_in 41322472
    a = 2
    print "re-point",id(a), id(2)   # re-point 41322448 41322448
print "func_out",id(a), id(1)  # func_out 41322472 41322472
fun(a)
print a  # 1
复制代码

这在很多语言中都是常识。我想不需要太多解释。第二个例子才是我们需要解释的

哈哈,上面那段写完我才对文中的代码进行调试,发现原来的语法还是 Python 2 的。所以重写了一遍,越写越觉得还有写东西需要问,所以上面那段代码改成了如下:

a = 1
def fun(a):
    print("fun_in: %s, %s" %(id(a), id(1)))
    a = 2
    print('re-point: %s, %s' %(id(a), id(2)))
print("fun_out: %s, %s" %(id(a), id(1)))
print("fun_out_2: %s" %id(2))
fun(a)
a = 2
print("fun_out_3: %s, %s, %s, %s" %(id(a), id(2), id(1), id(3)))
print a
复制代码

跑出来是这样的:

好吧,我又改了下:

a = 1
print('init: a: %s, 1: %s, 2: %s, 3: %s' %(id(a), id(1), id(2), id(3)))
def fun(a):
    print("fun_in: a: %s, 1: %s, 2: %s, 3: %s" %(id(a), id(1), id(2), id(3)))
    a = 2
    print('re_point: a: %s, 1: %s, 2: %s, 3: %s' %(id(a), id(1), id(2), id(3)))
fun(a)
print("fun_out: a: %s, 1: %s, 2: %s, 3: %s" %(id(a), id(1), id(2), id(3)))
a = 2
print("fun_out_2: a: %s, 1: %s, 2: %s, 3: %s" %(id(a), id(1), id(2), id(3)))
print a
复制代码

id 函数(Python 官方文档)的官方解释是返回一个对象在其生命周期唯一的“身份标识”。Cpython 实现中返回的是对象的物理地址。以上的代码比原先多了些读取对象 id 的地方。这里需要再来读下这句:指出所有的变量都可以理解为内存中一个对象的“引用”。那么其实可以看出来这里的 1, 2, 3 其实是所谓的对象(object),而 a 是所谓的变量(variable)。在赋值的过程中 a 相当于 C 语言中的一个指针,保存当前自己所指向对象 1 的地址。那么再声明一个变量 b,将它赋值为 1, 那么它的 id 也一定和对象 1 的一样。那么在程序运行过程中 python 解释器对于内存的分配与管理也很有意思。

现在写下这段的时候,我上面的那些代码截图是在 python 2.7.15 32位版本跑的。那么我之所以多写了个 3 也是想看下对于内存分配的问题。Windows 下 python 3.5.3 64位 vs python 2.7.15 32位,跑了几遍截图如下:

我的发现如下:

  1. 分配的 id 都是连续间隔的,python 2 32位间隔是 12, Python 3 64位的则是 32。
  2. Python 2 中从 1 到 3 id 值递减,Python 3 中则是递增。
  3. Python 3 中的 id 一直保持一致,Python 2 中则在不断变化。
  4. 然后我还加上了字符变量,再来一次。

这里我推测的原因:

  1. 连续的整形数成片分配空间
  2. 64位系统与 32位系统的差异。
  3. Python 版本导致对象分配内存差异。
  4. 从小到大的问题我一开始还以为是大端小端的问题,看来不是这个原因。
  5. 后面还需要加上浮点数,间隔整形数,字典,元组,数组,集合看下不同的情况(好吧感觉越写越多了)。

我想你能看到现在并能保持微笑的话真的心态好,我现在是脸上笑嘻嘻,心里MMP,写到12点多了,才发现呵呵呵呵了。第一天坑就有点挖大了,今晚先到这吧,MMP,睡觉去了!

文章分类
后端