4  变量和常用类型

本章节介绍Python中的变量和基础类型,完成本章之后,可以把Python当成计算器和草稿纸。本章没有要提交的课堂作业。

从这章起就要开始编程,有一件事要预先强调:所有语句中的符号都是英文,比如冒号,引号等等,达成中文符号是错误的一大来源。但vscode可能会提示你,后面大家会知道。

4.1 变量

前面说过,Python(或者其他编程语言)中的变量,和你数学课上的x, y, z是同类的概念。

正如前面的例子,Python使用等号=来为一个变量赋值

#%% 赋值与重新赋值
a = 1
a = 2
print(a)
2

假如这个变量a一开始不存在,那么赋值的同时,也会把这个变量创造出来。

对于Python语言,这个过程(不严格地说)大致是:

  1. (绑定)Python在电脑的内存空间找了一个空地,创建了一个对象(object),存放了1这个值,然后把a这个名字,和这个对象绑定起来。
  2. (重绑定)当我们对变量a赋其他值的时候,如a = 2的时候,Python另外创建了一个对象,存放了2这个值,然后把a这个名字,重新绑定到这个新的对象上。
  3. (引用)变量名,就像一个内存中的对象的标签。引用这个名字,就是引用其表示的对象。

4.1.1 删除一个变量

使用del语句

#%% 删除变量
a = 1
del a
print(a)

因为变量a已经被我们删除了,所以你再次引用a的时候,Python会告诉你,

NameError: name 'a' is not defined

4.1.2 常见错误name not defined

NameError: name 'xxx' is not defined

这个错误要告诉你,xxx这个东西,python找不到。这可能是:

  1. 打错字。例如你要引用一个名字叫apple,但输入成了appla。vscode会有提示。
  2. 代码存放在其他地方,没有import,后面会讲。
  3. 引用了一个不存在的变量。

稍微解释下第3点:

  1. 一个重新启动的Python交互环境,可以理解为一片白纸(其实不是完全是)。
  2. 第一次执行a = 1语句之后,a这个变量才会存在。
  3. .py文件中,有a=1这个语句,如果你不执行一次,内存中也不会有a

这表示,你只是打开一个.py文件,其实交互环境里面还是什么都没有, 这个时候print(a),就会提示找不到a

4.1.3 变量类型和动态语言

Python是一个“动态语言”,即Python的变量的类型是在运行过程中决定,或者说可以在运行中改变:你对这个变量赋什么值,这个变量就是什么类型。

查看变量类型的函数是type()

例如

#%% 动态类型
a = 1 
print(type(a))

a = 'apple' # 这里为a赋值了一个字符串
print(type(a))
<class 'int'>
<class 'str'>

显然,a先是一个整型int<class 'int'>,然后变成了一个字符串str<class 'str'>。 这和我们的赋值顺序是一样的。类型后面会详细说

注意:Python的变量类型是动态确定的。变量的类型不一定能从名字看出来,这是出错的一大来源。

4.2 数值

Python 3.x以后,数值类型有2种,整型int,和浮点型float

顾名思义,整型可以理解为整数:

#%% 整型
a = 1
print(type(a))
<class 'int'>

而浮点型则可以理解为小数:

#%% 浮点型
a = 1.23
print(type(a))
<class 'float'>

特别地,a = 1.0是什么类型?

a = 1.0
print(type(a))
<class 'float'>

显然,a是浮点型:只要你赋值的时候有小数点。 这可能是因为:

  1. 这个变量客观上是个小数,只是“恰好”是1而已。
  2. 或者这个数被四舍五入,比如本来是1.0000001之类。

4.2.1 数值的运算

  1. 常见的操作包括加减乘除+, -, *, /等等,此处不再重复。

特别地,除法永远返回浮点类型:

a = 4 / 2
print(a)
print(type(a))
2.0
<class 'float'>
  1. 整除是//。若除数是整型,则返回整型;若除数是浮点型,则返回浮点型
5 // 2
2
5 // 2.0
2.0
  1. 取余%
5 % 2
1
  1. 乘方 \(2^3\)
2 ** 3
8

4.2.2 小练习

求二元一次方程的根:

\[ 2x^2 + 5x - 3 = 0 \]

答案是(-3, 0.5)

4.3 字符串String

创建字符串,可以使用单引号、双引号、三单引号和三双引号。其中三引号可以多行定义字符串。

  1. 字符串:可以使用单引号、双引号
#%% 字符串
a = 'apple' # 或者:a = "apple"
print(a)
apple
  1. 多行字符串:可以使用三个单引号,或者三个双引号。
a = '''Hello 
Python
'''
print(a)
Hello 
Python

特别的,多行字符串也可以充当多行的注释:只要你不把字符串赋予一个变量, 这串字符串就对你的程序逻辑没什么影响,这就成了另一种注释。

常用于在模块(.py)文件的开头或者函数(后面会说)的开头,但实际上任何地方都可以。

4.3.1 字符串的常用操作

  1. 连接字符串 +
a = 'Hello'
b = 'Python'
print(a + b)
HelloPython

注:可以连加:a + b + c + d

  1. 其他常用操作
a = 'Hello Python'

print('lo' in a) # in: 是否存在

print(a.find('th') )# find():查找位置

print(a.replace('Python','Bob')) # replace():替换

print(a.lower()) # 转为小写:lower()

print(a.upper()) # 转为大写:upper()

print(" apple pie ".strip()) # 去除头尾的不可见字符(包括空格)
True
8
Hello Bob
hello python
HELLO PYTHON
apple pie
  1. 切片:截取字符串的一部分

后面讲列表List会详细介绍

4.3.2 显示特殊字符:转义字符\

  1. “换行\n
print("Hello\nPython")
Hello
Python
  1. 显示反斜杠、单引号、双引号等等

这些字符,本身已经是Python语法的一部分,要放在字符串中显示,需要转义,即在这个符号之前加反斜杠,如你要显示双引号,则可以使用\"

print('反斜杠\\') # 反斜杠 \\
print('\"双引号\"') # 双引号 \'
print('\'单引号\'') # 单引号 \"
反斜杠\
"双引号"
'单引号'

如果一下子看不清楚,应该如何书写:

  1. 作为字符串最外侧的单引号,或者双引号,必须对称
a = ' '
  1. 在单引号,或者双引号内,写入你要的文字
a = 'HelloWorld'
  1. 把转义字符看成一个整体,插入其中,如\n
a = 'Hello\nWorld'
print(a)
Hello
World
  1. 插入斜杠等,也是一样

4.3.3 字符串格式化

我们往往需要把一个变量插入一行字符中,例如我们想显示变量ab的值

#%% 简单加法
a = 1
b = 2
c = a + b
print(a)
print(b)
print(c)
1
2
3

会得到:

1
2
3

但问题是,你只看结果,其实分不清哪个是a,哪个是b,哪个是c。所以,我们更想要的是一句话,如

a的值是: 1
b的值是: 2
c的值是: 3

所以要用到字符串格式化,把变量和字符串混合。

#%% 简单加法
a = 1
b = 2
c = a + b
print('a的值是:{}\nb的值是:{}'.format(a,b))
a的值是:1
b的值是:2

解释一下:

  1. 首先,'a的值是:{}\nb的值是:{}',是一个字符串对象(object),注意两边的单引号。
  2. Str.format(),是字符串类型的一个方法(method),也可以称之为“成员函数”:函数名+小括号。
  3. 一个对象的方法,粗略地理解是:someone.do_something(),某样东西做了一件什么事。
  4. Str.format(),这个方法即一个“字符串格式化了自己”。具体的做法,是把format()的参数,这里是ab按顺序填进原字符串中的大括号{}中。 5.注意,我们使用了换行符\n

实际上,把字符串对象赋值给变量,如msg,那么msg就成了字符串类型(或者说指向了一个字符串对象),所以也可以这么做:

msg = 'a的值是:{}\nb的值是:{}'
print(msg.format(a,b))
a的值是:1
b的值是:2

还可以按参数的顺序(第一个元素是0):

msg = 'c的值是:{2}\na的值是:{0}\nb的值是:{1}'
print(msg.format(a,b,c))
c的值是:3
a的值是:1
b的值是:2

还有更简洁的办法”f-string”(需要python3.6版本或以上)

  1. 变量的开头(单引号或者双引号之前),加f,形成f'',即所谓”f-string”。
  2. 这种字符串在打印的时候,python会自动把对应的变量填充进去。
  3. 在中括号里直接填变量名
msg = f'a的值是:{a}\nb的值是:{b}'
print(msg)
a的值是:1
b的值是:2

实际上,你要在中括号里放其他python语句,例如其中做运算,也可以

msg = f'a + b的值是{a + b}'
print(msg)
a + b的值是3

如果只是要显示一个变量的名称,还有更简单的办法(需要Python 3.8或以上)

f{变量名=}

print(f'{a=}')
a=1

简单的数字格式化:变量后加{变量名:格式}

如只显示2位小数:0.2f

pi = 3.1415926535897
print(f"圆周率(保留2位小数)是{pi:0.2f}")
圆周率(保留2位小数)是3.14

如以百分数形式显示:%,保留2位小数是:.2%

z = 0.25
print(f"z是{z:.2%}")
z是25.00%

4.3.4 小练习

  1. 建立2个变量:nameid,分别赋值为你的姓名和学号。打印一个字符串,显示”学号:<你的学号>,姓名:<你的姓名>。”

  2. 圆的半径R=5,计算圆的面积area,并打印这句话,并保留2位小数:“半径为<圆的半径>的圆的面积是<圆的面积>”

4.4 布尔型Boolean

布尔型Boolean,也常简称为bool,逻辑关系,只有2个值:真True,或者假Falser colorize("注意区分大小写",'red')

一般用于条件判断(详细见后)

a = 1
b = 2

if a > b:
  print("a is bigger")

4.4.1 简单布尔运算

对于不熟悉编程的同学可能有点抽象。

and,或or,非not

  1. and,简称:“所有条件同时成立”(全部条件为True,会得到True;否则为False

如:“学号是单数”,且“坐在班级前排的同学”

print(True and True)
print(False and True)
print(False and False)
True
False
False
  1. or,简称:“最少有一个条件成立”(最少一个条件为True,会得到True;全部条件为False,则得到False
print(True or True)
print(False or True)
print(False or False)
True
True
False
  1. not:取反
print(not True)
print(not False)
False
True
  1. 举例:
a = 1
b = 2

a > b

(a > 1) and (b > 1)

(a > 1) or (b > 1)

not (b < 2)
True

r red("**注意**"):重点强调,必须留意运算符的优先级,先运算的部分要加括号!这和小学的数学运算是一样的。

4.5 None类型

空值,一切皆非。粗略地可以理解为一个“占位符”,例如一个不返回任何值的函数,以后遇到会再解释。

a = None
print(a)
None

4.6 简单类型转换

  1. 字符串和数值

字符串:可以表示词语、句子,可以拼接,组合 数字:可以运算

数字可以拼接吗?字符串可以做运算吗?

先转换一下类型

birth = "2001"

age = 2021 - birth
print(age)
TypeError: unsupported operand type(s) for -: 'int' and 'str'
NameError: name 'age' is not defined

一般而言,类型转换的函数,就是目标类型的名字。

把某个变量(如字符串str)转整型int,用函数int(),转为浮点是float()

birth = "2001"
age = 2021 - int(birth)
print(age)

age = 2021 - float(birth)
print(age)
20
20.0

显然反过来转换也是可以的,把某个变量转为字符串str()

print('Your age is ' + str(age))
Your age is 20.0
  1. 布尔型

(有逻辑学基础,可以快速过)

特别地,布尔型中,True可视为1False可视为0。 因此我们可以把数字的运算套用在布尔型上。

r red("注意"):要保持代码的清晰性,一般不建议使用布尔型进行运算,除非你很明白自己在做什么。

a = True # True可视为1
print(a + 1)

b = False # False可视为0
print(b - 1)
2
-1

做条件判断的时候,0会判定为False,非0会判断为True,这个我们后面说条件语句的时候会说。

if -1:
  print('hello')
hello

4.7 Python的类型转换和类型错误

Python是一个“动态类型+强类型”语言

  1. 动态类型:

变量名运行时绑定,变量名只是一个可以撕掉和重新粘贴的标签。你为某个变赋值什么类型,这个变量就是什么类型,在运行时可以随你的赋值代码而改变。

  1. 强类型:

一般情况下,Python不会为你自动转换类型(不会“隐式类型转换”)。

如一个很热门的语言JavaScript,大家现在上网看到的多数网站,其页面都是js语言写的。

在js中,一个字符”0”加一个数字1,js会自动(隐式地)把后者转换为字符串,然后进行拼接。

"0" + 1; // "01"

这其实对你的代码质量(如类型的检验)提出了更高要求,比如你的本意可能是要2个数字相加。

但这段代码会在你毫无知觉的情况下,一直运行下去,导致你可能要在无数代码执行过后,才发现问题。

在Python中,则会报错TypeError错误。

'0' + 1
TypeError: must be str, not int

显然,这说的是一个str,只能和另一个str相加(串联),而不能是一个int。 这个时候你应该用“显式”的类型转换。

如果看到TypeError,检查你的变量类型。