Python动态类型--变量、对象、引用的详细解释

特别说明,因为本篇文章第一次发布是在这里,所以,并没有检查。结果后来重新在微信公众号(Mark学编程)推送时,发现了一些错别字。所以,如果你对错别字很敏感,请到微信公众号(Mark学编程)阅读本篇文章,当然,那里还有更多的干货。

初学Python的,无不为变量,引用,对象这几个名词搞晕,并且在笔者看来,你很可能到现在为止也对变量这个词有误解。最起码笔者是这样的。直到有一天,笔者看到了英文版的Python书籍,里面较为详细的解释了Python的 Dynamic Typing,也就是动态类型。才彻底的明白了这些概念并且及时修正了以前脑中存在的一些误区。

开门见山先说变量,它来自英文的variable,翻译成中文叫做变量,翻译本身没有任何问题,但这种叫法,也许在其他语言中,比如C语言还有些意义,比如和常量比较而言,或者说因为他代表的内存区域的内容会不时变化等等。但到了Python,其实已经没有任何内存内容变化的意思,变量本身就是一个名字而已,这是不是有点毁你的三观,不用怀疑,请接阅读。但其实变量这个中文词汇很容易让人联想到内存中的数据是变动的,所以,可能会误认为变量是指内存中的数据,不是的,在Python里面,它不是指内存中的数据。这个已经在好几本权威的Python英文书中明确指出了,variable is just a name。但考虑到变量这个名词已经沿用很久,并且其他语言也广泛使用,笔者也无意去建议改动这个概念。但,我们必须明确,在Python中所谓的变量,就是名字,为了避免人们错误的联想,我下面会使用变量名这个词汇来表达变量。

下面的阐述,是我按照英文版Python手册中关于动态类型一章整理而成,在此感谢作者的指引。

在Python代码中,我们并不声明对象的具体类型,并且大部分程序甚至并不care具体类型。因为Python动态类型是其语言灵活性的根源,当然也是新手们的绊脚石。

学习其他语言的人遇见Python时,对其不声明类型可能感到困惑。在Python交互环境里或者文件里,当我们输入 a = 3 时,Python如何知道 a 代表整型呢?如果你这么发问,你就开始了解Python的动态类型模式了。在Python里,类型是在运行时自动判定的,不是对代码中声明的反应。这意味着,不需要事先声明变量(名)。

变量(名), 对象, 引用

a = 3
当运行这个赋值语句时,即使我们没有事先告诉Python我们要用a这个变量名,也没有告诉Python a 会代表什么类型,但Python却自然的认可名字和整型类型,就是基于以下三点:
(补充,again,翻译赋值语句是欠缺考虑的,赋值给人一种将值赋予给变量名的联想,不是很佳。如果你看英文原版,现在一般的都解释这种叫做“绑定”,而不是以前中文书中的赋值。其实,assignment本身更多的意思是分派,分配的意思。)

  1. 变量(名)创建:
    A variable (i.e., name), like a, is created when your code first assigns it a value. Future assignments change the value of the already created name. Technically, Python detects some names before your code runs, but you can think of it as though initial assignments make variables
    为了增加权威性,我直接复制了英文原文。
    大体意思是,变量(也就是名字)a 是在绑定值(对象)3的时候创建的。将来a可以绑定其他的值(对象)。尽管Python会对某些名字事项探测,但总体上我们就这么认为,绑定语句创建了变量(名)。

  2. 变量类型
    变量(名)并没有什么类型,类型的概念只是与对象有关,而不是名字。变量名只是指向(绑定)特定时间中的特定的对象。

  3. 变量名的使用:
    当变量名在表达式中出现时,会被它指向的对象所代替。更进一步的,变量名必须在使用前绑定(指向)对象,否则报错。
    再看例子:
    a = 3
    它就是将名字a绑定到对象(3)上。
    它做三件事:

    1. 创建对象代表3(补充,和C语言等不一样,这个对象要比单纯3的值内容多,后面会提到,所以叫Object,不仅仅是值)
    2. 创建变量名a, 如果它已经存在,那就解除之前的绑定,来绑定这个3对象。
    3. 连接(绑定)变量名和对象3.
      Python动态类型--变量、对象、引用的详细解释_第1张图片
      注意几点:变量名与对象不再同一内存中,对象比单纯3这个值面积大,暗示还有其他内容,下面会提到。变量名本质是个名字并且引用对象,就像C语言中的指针,但是我们没有必要理解所谓的指针。就理解成引用,指向等即可。
      还有一点特别重要,变量名只能指向对象,而不能指向另一个变量名。
      并且,大的对象里面可能有更多的指向,比如一个变量名指向一个列表,而列表里面的元素本身是一个对象,里面的元素名就指向里面元素对象。这个后面会讲到。
      这种从变量名到对象的连接就做引用。从概念上来讲,每一次代码运行一个表达式,Python就创建一个对象(一片内存区域),当然,对有些简单的数据Python是重复使用的,并不是更创建一个内存区域,比如 想5这样的整型。简单的字符串等。这个可以使用id来看,同样的对象是否是同样的id。只要是复杂的对象,尽管内容相同,id是不一样的,就是不是一个对象。但是逻辑上,每次创建的对象是不同的。
      另外,对象除了包含值以外,还有type designator 和 reference counter 两个头部。上面已经提到,这是不同于C语言的设计,所以Python叫做object(中文翻译成了对象,起初感觉翻译一般,但后来觉得中文没有更合适的词汇了。其实笔者也已经习惯了这个词)。
      是对象而不是变量名包含类型的内容。上面提到的对象头部有类型标签。这个类型决定了对象的各类操作。比如字符串类型有这样的方法和计算方式,列表有那样的方法和计算方式等等。学习了类,就可以自行定义类型并且定义其操作方法计算方法了。
      对象头部还包含计数器,是和对象的回收有关的,这个其实不用了解了,不影响对Python的理解。

共享引用 shared references

我们看下面的代码
a = 3
b = a

Python动态类型--变量、对象、引用的详细解释_第2张图片
这里的重点是在运行 b = a 后,a, b 并没有什么直接联系,而是a, b同时引用一个同样的对象,或者说同一个对象有两个名字。
用其中的一个名字都可以操作对象(改变对象。
Python动态类型--变量、对象、引用的详细解释_第3张图片
上面的图展示了当 a 绑定了新的对象后的情景。

再看下面的这些语句
a = 3
b = a
a = a + 3
请注意,第三行的a 已经解除了与3的绑定,指向了一个新的对象 5 上面了。b 仍然指向 3.
这是当对象为不可变对象时的情景。

当对象为可能对象时,(mutable objects)如果做就地改变,那么画风就不一样了,请往下看:

Shared References and In-Place Changes
列表,字典,集合都属于mutable type,可变类型。
当我们这样做时,
list1 = [2,3,5]
list2 = list1
list1 = 24
这个时候,list1就成为新的列表,这个和上面的不可变类型是一样的。
但是,如果我们改变列表其中的元素,叫做就地改变(in-place change),那么:
list1 = [2,3,5]
list2 = list1
list2[0] = 24
list1
list2
都发生了改变。这个应该容易理解吧,因为他们都只想同一个列表对象。
如果你在改变时,不愿意改变原来的列表,那么久这么做:
list1 = [2,3,5]
list2 = list1[:] 这就复制了列表1;
list2[0] = 24
list2改变了,但是list1并没有改变。因为这个复制,使得list1和list2并没有指向同一个列表。因为list2是复制了list1,形成了一个新的列表,可以用id来观察。

差不多了,主要的内容都覆盖了,下面是三道小题,供测试使用:

  1. A = “spam”
    B = A
    B = “Good”
    A的值变了吗?
  2. A = [“spam”]
    B = A
    B[0] = “Good”
    A 的值变了吗?
  3. A = [“spam”]
    B = A[:]
    B[0] = “Good”
    A 的值变了吗?

就到这里,欢迎提出反馈意见。并且适当转发给你的小伙伴们,让大家一起来学习Python。

你可能感兴趣的:(教程,Python,引用赋值)