初学者专题:变量和赋值
2020-05-22
作者:老齐
对于初学Python者,除了看书(《跟老齐学Python:轻松入门》或者《Python大学实用教程》,均为电子工业出版社出版)、或者看视频(网易云课堂、CSDN上均有老齐的视频课程),还要进行专题性总结。比如本文,就是要帮助学习者,对变量和赋值这两个非常基本、几乎无处不在的内容作为一个专题进行总结。
对象
Python语言既能够实现面向过程,也能够实现面向对象编程。而面向对象,是当前软件开发的主流编程思想。在我的两本书中,我都强调了面向对象——不要认为这种编程思想不适用于初学者,更不要认为它有多难。
并且,Python语言中已经有这样一个明确的概念:万物皆对象,不论是数字、整数、函数、类,等等,都是对象。
Python语言中的对象,可以理解为语言中的“实际物体”,它一经创建,存储器中就开辟出一个空间保存它,因而也就有了一个内存地址。
比如:
1 | >>> id(3.14) |
这里返回的十进制数字,就代表了存储器为浮点数对象3.14
分配的内存地址。
另外,Python中的任何对象都有类型。在Python中,类型就是类。在Python创立之初,这两个没有统一,后来将“类”和“类型”统一了起来,这样我们就可以把每一个具体的数据,看成是某个“类”的实例,而那个“类”就是这个实例的“类型”。
比如:
1 | >>> type(3.14) |
返回值显示,3.14
是float
类的实例,也就是float
类型。
下面自定义一个类,然后创建实例,再看看那个实例的类型:
1 | >>> class Book: |
除了返回的类的具体内容不同之外,Book()
(注意,这是对象,my_book
引用了这个对象,所以,也可以说是my_book
,对此的详细说明请阅读本文后续内容)和3.14
都是所对应类的实例——返回值格式相同,因此它们也都是所对应类的那种“类型”。
变量
在Python中使用变量,非常方便,可以用“召之即来挥之即去”形容,也就是不需要“创建”变量,用的时候信手拈来。
1 | >>> int a |
在有些语言里面,比如Java,要使用某个变量,必须先创建它。但是,如果把这个习惯搬到Python中,就如同上面操作那样,会报错。另外,还要注意,Python中的变量不是对象,它不能单独存在。
1 | >>> a |
上面的演示,就是想用一个变量a
,但是,只是把它单独放在那里,就如同在数学上,“假设变量a”,这样做是不行的。在Python中,变量必须和某个对象关联起来。
1 | >>> a = 2 |
在上面的示例中,a=2
就是将变量a
与对象2
关联了起来。注意,这里的变量a
不是像容器那样,将对象2
放入其中,而是如同标签那样,贴到了对象2
上,于是乎通过这个标签就可以找到那个对象。
id(a)
并不是返回变量a
的内存地址——它不是对象,而是返回了它所引用的对象2
的内存地址。再参考后面的id(2)
,可以看到两者内存地址一样,也就是说证明了a
这个变量引用的对象就是2
。
但是,如果在交互模式中,做下面的操作,就令人匪夷所思了。
1 | >>> a = 1.23 |
按照前面的说法,这个怎么解释?!
再解释这个之前,先来看下面的操作。
创建一个文件,比如命名为idvalue.py
,然后在文件中写入如下代码:
1 | #coding:utf-8 |
这段程序,跟前面交互模式里面的一样。但是,请注意接下来的事情。保存文件之后,执行它。
1 | % python3 idvalue.py |
看执行结果。这里得到的a
和1.23
的内存地址居然是一样的。
tu
神奇吗?
要解释这种神奇,话就有点长了,要从交互模式的特点开始说起。交互模式,是我们学习和做简单练习的好地方,但是,它有一个缺点,“记忆力太差”,每一行执行完毕,就会将该行“忘记”,下一行又从头开始。当执行了a = 1.23
之后,本来内存中已经创建了1.23
这个对象,但是,当再次执行id(1.23)
时,因为两个不完全一样,交互模式的解析器忘记了前面的1.23
,于是乎又在存储器中重新创建了id(1.23)
中的1.23
对象。
可为什么a = 2
不如此呢?因为Python还有一个习惯,把-256~256这些整数,在内存中有“常住户口”。
1 | >>> b = 256 |
但是,如果在一个程序文件里,Python解析器的“记忆力”就正常了,不会重复创建同样的对象——当然,如拷贝等有意为之的除外。
至此,我们已经明确,Python中的变量和对象之间是引用关系,正式因为这种引用关系,让Python中实现某些操作就非常容易了。
1 | >>> first = 1 |
在这个示例中,变量first
引用了1
,second
引用了2
,如果想把这两个变量引用的对象对调一下,在Python里面使用first, second = second, first
。这是多么简单、优雅、直接呀。如果在Java里面,就麻烦了——学过C/C++/Java等语言的同学,试一试吧。
由此,我们可以放胆说:Python简单、优雅。
还是因为“引用”,一个对象可以被多个变量引用,就相当于一个物体上可以贴多个标签那样。
1 | >>> a = b = 3.14 |
“变量引用对象”这个思想,还可以扩展到函数的参数。有的人习惯把函数的参数弄很多名称,比如形参、实参等,并且进行区分。在Python语言中,它们本质上都是变量,只不过是在函数作用于里面使用的变量。当定义函数的时候,虽然那个变量也没有引用对象,但因为是定义函数,这个函数并没有执行,所以,一个没有引用对象的变量是许可存在的。
1 | >>> book = ['python',] |
上面代码中,第1行创建了一个列表。第2行开始,创建了一个函数,参数是b
——这时候称为“形参”,即形式上的参数。其实,因为这个函数并没有调用,所以,那个变量b
可以认为是占位符,可以单独存在,不需要引用任何对象。
后面,调用这个函数my_book(book)
。这里我们通常形象而简要地说:“将boo
传给函数”。这句话其实不是很严谨,但它因为形象简短,所以被广为使用。如果严谨地说——未免啰嗦了,调用这个函数后,发生的是:b
引用了变量book
所引用的对象['python',]
。
从后面的执行结果中可以看出,因为函数内和函数外,不同变量引用的对象都是同一个,所以,会发生同样的变化。
对于变量,最后要强调的就是命名习惯:
- 非数字开头
- 字母都小写
- 用有意的单词或者单词组合,多个单词之间用
_
连接 - 避免使用与下列项目冲突的单词:内置类型、内置函数、关键词
以下是列出Python关键词的方法:
1 | >>> import keyword |
或者:
1 | >>> help("keywords") |
有一种常见情况,如下所示:
1 | >>> list = [1,2,3] |
这就是因为本来的内置对象类型list
,或者内置函数的名称,已经被>>> list = [1,2,3]
占用了,后面再使用list
,指的就是这个列表。所以,第二行的操作中会报错。
tu
赋值
在理解变量和对象关系的基础上,理解“赋值”或“赋值语句”就简单多了,从本质上讲,赋值就是变量与某对象建立引用关系,只不过,这里不是如前面所说的某个直接的对象,这里的对象可能是经过计算之后得到的,所以,先要知道“表达式”。
所谓表达式,就是对象间用操作符连接,组成一个有意义的式子。
1 | >>> 1 + 2 |
以上演示的都是表达式,一般而言,表达式要返回一个对象。如果将这个对象再被变量引用,就成为了“赋值”。
1 | >>> py = "python" + "lang" |
当然,前面出现的诸如a = 2
也都是赋值语句。
在赋值语句中,=
的作用于数学中的等号有很大区别,它表示将变量与对象之间建立引用关系。
1 | >>> n = 1 |
对于表达式n = n + 1
,这里的=
如果是数学中的意义,那么就会出现0=1
。
对于n = n + 1
这种操作,还可以写成:
1 | >>> n += 1 |
这种写法称为自增,同样,减、乘、除也都有类似的操作。
对于赋值,必须要说明的是Python3.8中新增的功能:海象运算符。
1 | >>> n = len('python') |
在第二行开始的条件语句中,要使用n
,必须要要在前面通过赋值语句获得。Python3.8的海象赋值运算符,把上面的赋值那一行和第二行融合起来,让代码更简洁。
1 | >>> if (i := len('python')) < 10: |
关于海象运算符,本微信公众号有专门文章阐述,请参阅:《Python3.8新语法:海象运算符》
最后,要强调的是,Python中函数、类也都是对象,它们同样能够用于赋值语句。
1 | >>> lam = lambda x: x+3 |
第一行创建了一个lambda函数,这个函数对象用变量lam
引用,也是赋值。注意第三行,只有名称才引用对象,如果是lam()
,是试图要执行lam
引用的对象,所以,q = lam
才是赋值,或者说变量q
也引用了这个lambda函数。
本文对变量和赋值做了专题总结,供初学者复习,以便加深对相关知识的理解。
专注于软件和AI的公众号
老齐教室
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
关注微信公众号,读文章、听课程,提升技能