CH03_变量和运算符


本章目标

  • 掌握python的语法规范
  • 掌握变量的运用
  • 掌握各类运算符的运用

python语法规范

注释

注释(Comments)用来向用户提示或解释某些代码的作用和功能,它可以出现在代码中的任何位置。Python 解释器在执行代码时会忽略注释,不做任何处理,就好像它不存在一样。

在调试(Debug)程序的过程中,注释还可以用来临时移除无用的代码。

注释的最大作用是提高程序的可读性,没有注释的程序简直就是天书,让人吐血!

千万不要认为你自己写的代码规范就可以不加注释,甩给别人一段没有注释的代码是对别人的不尊重,是非常自私的行为;你可以喜欢自虐,但请不要虐待别人。

很多程序员宁愿自己去开发一个应用,也不愿意去修改别人的代码,没有合理的注释是一个重要的原因。虽然良好的代码可以自成文挡,但我们永远不清楚今后阅读这段代码的人是谁,他是否和你有相同的思路;或者一段时间以后,你自己也不清楚当时写这段代码的目的了。

一般情况下,合理的代码注释应该占源代码的 1/3 左右。

Python 支持两种类型的注释,分别是单行注释和多行注释。

单行注释

Python 使用井号#作为单行注释的符号,语法格式为:

1
># 注释内容

从井号#开始,直到这行结束为止的所有内容都是注释。Python 解释器遇到#时,会忽略它后面的整行内容。

1
2
3
4
5
6
7
8
9
>#使用print输出字符串
>print("Hello World!")
>print("广创科技教育")
>print("http://os-guangchuang.gitee.io/note")

>#使用 print输出数字
>print(100)
>print( 3 + 100 * 2)
>print( (3 + 100) * 2 )

说明单行代码的功能时一般将注释放在代码的右侧,例如:

1
2
3
>print("http://os-guangchuang.gitee.io/note")  #输出课程地址
>print( 36.7 * 14.5 ) #输出乘积
>print( 100 % 7 ) #输出余数

多行注释

多行注释指的是一次性注释程序中多行的内容(包含一行)。 Python 使用三个连续的单引号’’’或者三个连续的双引号”””注释多行内容,具体格式如下:

1
2
3
4
5
>'''
>使用 3 个单引号分别作为注释的开头和结尾
>可以一次性注释多行内容
>这里面的内容全部是注释内容
>'''

或者

1
2
3
4
5
>"""
>使用 3 个双引号分别作为注释的开头和结尾
>可以一次性注释多行内容
>这里面的内容全部是注释内容
>"""

多行注释通常用来为 Python 文件、模块、类或者函数等添加版权或者功能描述信息。

注意事项

  1. Python 多行注释不支持嵌套,所以下面的写法是错误的:
1
2
3
4
5
6
'''
外层注释
'''
内层注释
'''
'''
  1. 不管是多行注释还是单行注释,当注释符作为字符串的一部分出现时,就不能再将它们视为注释标记,而应该看做正常代码的一部分,例如:
1
2
3
print('''Hello,World!''')
print("""http://os-guangchuang.gitee.io/note""")
print("#是单行注释的开始")

通过注释辅助调试

给代码添加说明是注释的基本作用,除此以外它还有另外一个实用的功能,就是用来调试程序。

举个例子,如果你觉得某段代码可能有问题,可以先把这段代码注释起来,让 Python 解释器忽略这段代码,然后再运行。如果程序可以正常执行,则可以说明错误就是由这段代码引起的;反之,如果依然出现相同的错误,则可以说明错误不是由这段代码引起的。

在调试程序的过程中使用注释可以缩小错误所在的范围,提高调试程序的效率。

缩进规则

和其它程序设计语言(如 Java、C 语言)采用大括号“{}”分隔代码块不同,Python 采用代码缩进和冒号( : )来区分代码块之间的层次。

在 Python 中,对于类定义、函数定义、流程控制语句、异常处理语句等,行尾的冒号和下一行的缩进,表示下一个代码块的开始,而缩进的结束则表示此代码块的结束。

注意,Python 中实现对代码的缩进,可以使用空格或者 Tab 键实现。但无论是手动敲空格,还是使用 Tab 键,通常情况下都是采用 4 个空格长度作为一个缩进量(默认情况下,一个 Tab 键就表示 4 个空格)。

例如,下面这段 Python 代码中(涉及到了目前尚未学到的知识,初学者无需理解代码含义,只需体会代码块的缩进规则即可):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
height=float(input("输入身高:")) #输入身高
weight=float(input("输入体重:")) #输入体重
bmi=weight/(height*height) #计算BMI指数

#判断身材是否合理
if bmi<18.5:
#下面 2 行同属于 if 分支语句中包含的代码,因此属于同一作用域
print("BMI指数为:"+str(bmi)) #输出BMI指数
print("体重过轻")
if bmi>=18.5 and bmi<24.9:
print("BMI指数为:"+str(bmi)) #输出BMI指数
print("正常范围,注意保持")
if bmi>=24.9 and bmi<29.9:
print("BMI指数为:"+str(bmi)) #输出BMI指数
print("体重过重")
if bmi>=29.9:
print(BMI指数为:"+str(bmi)) #输出BMI指数
print("肥胖")

Python 对代码的缩进要求非常严格,同一个级别代码块的缩进量必须一样,否则解释器会报 SyntaxError 异常错误。例如,对上面代码做错误改动,将位于同一作用域中的 2 行代码,它们的缩进量分别设置为 4 个空格和 3 个空格,如下所示:

1
2
3
if bmi<18.5:
print("BMI指数为:"+str(bmi)) #输出BMI指数
print("体重过轻")

可以看到,第二行代码和第三航代码本来属于同一作用域,但我们手动修改了各自的缩进量,这会导致 SyntaxError 异常错误,如图 1 所示。

对于 Python 缩进规则,初学者可以这样理解,Python 要求属于同一作用域中的各行代码,它们的缩进量必须一致,但具体缩进量为多少,并不做硬性规定。

IDLE 开发环境对缩进量的设置

​ 在 IDLE 开发环境中,默认是以 4 个空格作为代码的基本缩进单位。不过,这个值是可以手动改变的,在菜单栏中选择Options -> Configure,会弹出如下对话框:

如图所示,通过拖动滑块,即可改变默认的代码缩进量,例如拖动至 2,则当你使用 Tab 键设置代码缩进量时,会发现按一次 Tab 键,代码缩进 2 个空格的长度。

不仅如此,在使用 IDLE 开发环境编写 Python 代码时,如果想通过设置多行代码的缩进量,可以使用 Ctrl+] 和 Ctrl+[ 快捷键,此快捷键可以使所选中代码快速缩进(或反缩进)。

编码规范

在讲解具体的 Python 编码规范之前,先来看看图 1 中的代码:

对比图 1 中的两段代码你会发现,它们所包含的代码时完全相同的,但很明显,右侧的代码编写格式看上去比左侧的代码段更加规整,阅读起来也会比较轻松、畅快,因为它遵循了最基本的 Python 代码编写规范。

Python 采用 PEP 8 作为编码规范,其中 PEP 是 Python Enhancement Proposal(Python 增强建议书)的缩写,8 代表的是 Python 代码的样式指南。下面仅给大家列出 PEP 8 中初学者应严格遵守的一些编码规则:

  1. 每个 import 语句只导入一个模块,尽量避免一次导入多个模块,例如:
1
2
3
4
5
#推荐
import os
import sys
#不推荐
import os,sys
  1. 不要在行尾添加分号,也不要用分号将两条命令放在同一行,例如:
1
2
#不推荐
height=float(input("输入身高:")) ; weight=fioat(input("输入体重:")) ;
  1. 建议每行不超过 80 个字符,如果超过,建议使用小括号将多行内容隐式的连接起来,而不推荐使用反斜杠 \ 进行连接。例如,如果一个字符串文本无法实现一行完全显示,则可以使用小括号将其分开显示,代码如下:
1
2
3
4
5
6
#推荐
s=("Note电子笔记网站是各语言程序设计专业网站,"
"提供java、python、c#、html等。")
#不推荐
s="Note电子笔记网站是各语言程序设计专业网站,\
提供java、python、c#、html等。"
  1. 使用必要的空行可以增加代码的可读性,通常在顶级定义(如函数或类的定义)之间空两行,而方法定义之间空一行,另外在用于分隔某些功能的位置也可以空一行。比如说,在图 1 右侧这段代码中,if 判断语句同之前的代码多实现的功能不同,因此这里可以使用空行进行分隔。

  2. 通常情况下,在运算符两侧、函数参数之间以及逗号两侧,都建议使用空格进行分隔。

标识符命名规范

简单地理解,标识符就是一个名字,就好像我们每个人都有属于自己的名字,它的主要作用就是作为变量、函数、类、模块以及其他对象的名称。

Python 中标识符的命名不是随意的,而是要遵守一定的命令规则,比如说:

  1. 标识符是由字符(AZ 和 az)、下划线和数字组成,但第一个字符不能是数字。
  2. 标识符不能和 Python 中的保留字相同。有关保留字,后续章节会详细介绍。
  3. Python中的标识符中,不能包含空格、@、% 以及 $ 等特殊字符。

例如,下面所列举的标识符是合法的:

1
2
3
4
>UserID
name
mode12
user_age

以下命名的标识符不合法:

1
2
3
>4word    #不能以数字开头
>try #try是保留字,不能作为标识符
>$money #不能包含特殊字符

1.在 Python 中,标识符中的字母是严格区分大小写的,也就是说,两个同样的单词,如果大小格式不一样,多代表的意义也是完全不同的。比如说,下面这 3 个变量之间,就是完全独立、毫无关系的,它们彼此之间是相互独立的个体。

1
2
3
>>number = 0
Number = 0
NUMBER = 0

2.Python 语言中,以下划线开头的标识符有特殊含义,例如:

  • 以单下划线开头的标识符(如 _width),表示不能直接访问的类属性,其无法通过 from…import* 的方式导入;
  • 以双下划线开头的标识符(如__add)表示类的私有成员;
  • 以双下划线作为开头和结尾的标识符(如 __init__),是专用标识符

因此,除非特定场景需要,应避免使用以下划线开头的标识符。

另外需要注意的是,Python 允许使用汉字作为标识符,例如:

1
>笔记网="os-guangchuang.gitee.io/note"

但我们应尽量避免使用汉字作为标识符,这会避免遇到很多奇葩的错误。

标识符的命名,除了要遵守以上这几条规则外,不同场景中的标识符,其名称也有一定的规范可循,例如:

  • 当标识符用作模块名时,应尽量短小,并且全部使用小写字母,可以使用下划线分割多个字母,例如 game_mian、game_register 等。
  • 当标识符用作包的名称时,应尽量短小,也全部使用小写字母,不推荐使用下划线,例如 com.mr、com.mr.book 等。
  • 当标识符用作类名时,应采用单词首字母大写的形式。例如,定义一个图书类,可以命名为 Book。
  • 模块内部的类名,可以采用 “下划线+首字母大写” 的形式,如 _Book;
  • 函数名、类中的属性名和方法名,应全部使用小写字母,多个单词之间可以用下划线分割;
  • 常量命名应全部使用大写字母,单词之间可以用下划线分割;

关键字和保留字

保留字是 Python 语言中一些已经被赋予特定意义的单词,这就要求开发者在开发程序时,不能用这些保留字作为标识符给变量、函数、类、模板以及其他对象命名。

Python 包含的保留字可以执行如下命令进行查看:

1
2
3
>>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

需要注意的是,由于 Python 是严格区分大小写的,保留字也不例外。所以,我们可以说 if 是保留字,但 IF 就不是保留字。

在实际开发中,如果使用 Python 中的保留字作为标识符,则解释器会提示“invalid syntax” 的错误信息,如图 2 所示。

内置函数

Python 解释器自带的函数叫做内置函数,这些函数可以直接使用,不需要导入某个模块。

变量

变量的定义和使用

变量(Variable)可以看成一个小箱子,专门用来“盛装”程序中的数据。每个变量都拥有独一无二的名字,通过变量的名字就能找到变量中的数据。

从底层看,程序中的数据最终都要放到内存(内存条)中,变量其实就是这块内存的名字。

和变量相对应的是常量(Constant),它们都是用来“盛装”数据的小箱子,不同的是:变量保存的数据可以被多次修改,而常量一旦保存某个数据之后就不能修改了。

变量的赋值

​ 在编程语言中,将数据放入变量的过程叫做赋值(Assignment)。Python 使用等号=作为赋值运算符,具体格式为:

1
>name = value

例如,下面的语句将整数 10 赋值给变量 n:

1
>n = 10

除了赋值单个数据,你也可以将表达式的运行结果赋值给变量,例如:

1
2
3
>sum = 100 + 20  #将加法的结果赋值给变量
>rem = 25 * 30 % 7 #将余数赋值给变量
>str = "note笔记网" + "http://os-guangchuang.gitee.io/note" #将字符串拼接的结果赋值给变量

变量的使用

​ 使用 Python 变量时,只要知道变量的名字即可。 几乎在 Python 代码的任何地方都能使用变量,请看下面的演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>>> n = 10
>>>> print(n) #将变量传递给函数
>10
>>>> m = n * 10 + 5 #将变量作为四则运算的一部分
>>>> print(m)
>105
>>>> print(m-30) #将由变量构成的表达式作为参数传递给函数
>75
>>>> m = m * 2 #将变量本身的值翻倍
>>>> print(m)
>210
>>>> url = "http://os-guangchuang.gitee.io/note"
>>>> str = "note笔记网:" + url #字符串拼接
>>>> print(str)
>note笔记网:http://os-guangchuang.gitee.io/note

python是若类型的语言

在强类型的编程语言中,定义变量时要指明变量的类型,而且赋值的数据也必须是相同类型的,C语言、C++、Java 是强类型语言的代表。

下面我们以 C++ 为例来演示强类型语言中变量的使用:

1
2
3
4
5
>int n = 10;  //int表示整数类型
>n = 100;
>n = "张三"; //错误:不能将字符串赋值给整数类型

>url = "http://www.baidu.com"; //错误:没有指明类型的变量是没有定义的,不能使用。

和强类型语言相对应的是弱类型语言,Python、JavaScript、PHP 等脚本语言一般都是弱类型的。

弱类型语言有两个特点:

  • 变量无须声明就可以直接赋值,对一个不存在的变量赋值就相当于定义了一个新变量。
  • 变量的数据类型可以随时改变,比如,同一个变量可以一会儿被赋值为整数,一会儿被赋值为字符串。

注意,弱类型并不等于没有类型!弱类型是说在书写代码时不用刻意关注类型,但是在编程语言的内部仍然是有类型的。我们可以使用 type() 内置函数类检测某个变量或者表达式的类型,例如:

1
2
3
4
5
6
7
8
9
10
11
>>>> num = 10
>>>> type(num)
><class 'int'>
>>>> num = 15.8
>>>> type(num)
><class 'float'>
>>>> num = 20 + 15j
>>>> type(num)
><class 'complex'>
>>>> type(3*15.6)
><class 'float'>

数据类型

整数类型(int)

整数就是没有小数部分的数字,Python 中的整数包括正整数、0 和负整数。

有些强类型的编程语言会提供多种整数类型,每种类型的长度都不同,能容纳的整数的大小也不同,开发者要根据实际数字的大小选用不同的类型。例如C语言提供了 short、int、long、long long 四种类型的整数,它们的长度依次递增,初学者在选择整数类型时往往比较迷惑,有时候还会导致数值溢出。

而 Python 则不同,它的整数不分类型,或者说它只有一种类型的整数。Python 整数的取值范围是无限的,不管多大或者多小的数字,Python 都能轻松处理。

代码案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>#将 78 赋值给变量 n
>n = 78
>print(n)
>print( type(n) )

>#给x赋值一个很大的整数
>x = 8888888888888888888888
>print(x)
>print( type(x) )

>#给y赋值一个很小的整数
>y = -7777777777777777777777
>print(y)
>print( type(y) )

运行结果:

1
2
3
4
5
6
>78
<class 'int'>
8888888888888888888888
<class 'int'>
-7777777777777777777777
<class 'int'>

x 是一个极大的数字,y 是一个很小的数字,Python 都能正确输出,不会发生溢出,这说明 Python 对整数的处理能力非常强大。

不管对于多大或者多小的整数,Python 只用一种类型存储,就是 int。

整数的不同进制:

1.十进制形式

​ 我们平时常见的整数就是十进制形式,它由 0~9 共十个数字排列组合而成。

​ 注意,使用十进制形式的整数不能以 0 作为开头,除非这个数值本身就是 0。

2.二进制形式

​ 由 0 和 1 两个数字组成,书写时以0b0B开头。例如,101 对应十进制数是 5。

3.八进制形式

​ 八进制整数由 0~7 共八个数字组成,以0o0O开头。注意,第一个符号是数字 0,第二个符号是大写或小写的字母 O。

4.十六进制形式

​ 由 09 十个数字以及 AF(或 a~f)六个字母组成,书写时以0x0X开头,

代码案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>#十六进制
>hex1 = 0x45
>hex2 = 0x4Af
>print("hex1Value: ", hex1)
>print("hex2Value: ", hex2)

>#二进制
>bin1 = 0b101
>print('bin1Value: ', bin1)
>bin2 = 0B110
>print('bin2Value: ', bin2)

>#八进制
>oct1 = 0o26
>print('oct1Value: ', oct1)
>oct2 = 0O41
>print('oct2Value: ', oct2)

运行结果:

1
2
3
4
5
6
>hex1Value:  69
hex2Value: 1199
bin1Value: 5
bin2Value: 6
oct1Value: 22
oct2Value: 33

数字分隔符:

​ 为了提高数字的的可读性,Python 3.x 允许使用下划线_作为数字(包括整数和小数)的分隔符。通常每隔三个数字添加一个下划线,类似于英文数字中的逗号。下划线不会影响数字本身的值。

代码案例:

1
2
3
4
>click = 1_301_547
>distance = 384_000_000
>print("Python教程阅读量:", click)
>print("地球和月球的距离:", distance)

运行结果:

1
2
>Python教程阅读量:1301547
>地球和月球的距离:384000000

小数/浮点数(float)

​ 在编程语言中,小数通常以浮点数的形式存储。浮点数和定点数是相对的:小数在存储过程中如果小数点发生移动,就称为浮点数;如果小数点不动,就称为定点数。

Python 中的小数有两种书写形式:

1.十进制形式:

这种就是我们平时看到的小数形式,例如 34.6、346.0、0.346。

书写小数时必须包含一个小数点,否则会被 Python 当作整数处理。

2.指数形式

​ Python 小数的指数形式的写法为:

1
>>aEn 或 aen

a 为尾数部分,是一个十进制数;n 为指数部分,是一个十进制整数;Ee是固定的字符,用于分割尾数部分和指数部分。整个表达式等价于 a×10n。

​ 指数形式的小数举例:

  • 2.1E5 = 2.1×105,其中 2.1 是尾数,5 是指数。
  • 3.7E-2 = 3.7×10-2,其中 3.7 是尾数,-2 是指数。
  • 0.5E7 = 0.5×107,其中 0.5 是尾数,7 是指数。

注意,只要写成指数形式就是小数,即使它的最终值看起来像一个整数。例如 14E3 等价于 14000,但 14E3 是一个小数。

Python 只有一种小数类型,就是 float。C语言有两种小数类型,分别是 float 和 double:float 能容纳的小数范围比较小,double 能容纳的小数范围比较大。

代码案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
>f1 = 12.5
>print("f1Value: ", f1)
>print("f1Type: ", type(f1))

>f2 = 0.34557808421257003
>print("f2Value: ", f2)
>print("f2Type: ", type(f2))

>f3 = 0.0000000000000000000000000847
>print("f3Value: ", f3)
>print("f3Type: ", type(f3))

>f4 = 345679745132456787324523453.45006
>print("f4Value: ", f4)
>print("f4Type: ", type(f4))

>f5 = 12e4
>print("f5Value: ", f5)
>print("f5Type: ", type(f5))

>f6 = 12.3 * 0.1
>print("f6Value: ", f6)
>print("f6Type: ", type(f6))

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
>f1Value:  12.5
f1Type: <class 'float'>
f2Value: 0.34557808421257
f2Type: <class 'float'>
f3Value: 8.47e-26
f3Type: <class 'float'>
f4Value: 3.456797451324568e+26
f4Type: <class 'float'>
f5Value: 120000.0
f5Type: <class 'float'>
f6Value: 1.2300000000000002
f6Type: <class 'float'>

从运行结果可以看出,Python 能容纳极小和极大的浮点数。print 在输出浮点数时,会根据浮点数的长度和大小适当的舍去一部分数字,或者采用科学计数法。 f5 的值是 120000,但是它依然是小数类型,而不是整数类型。

​ 让人奇怪的是 f6,12.3*0.1的计算结果很明显是 1.23,但是 print 的输出却不精确。这是因为小数在内存中是以二进制形式存储的,小数点后面的部分在转换成二进制时很有可能是一串无限循环的数字,无论如何都不能精确表示,所以小数的计算结果一般都是不精确的。

复数类型(complex)

复数(Complex)是 Python 的内置类型,直接书写即可。换句话说,Python 语言本身就支持复数,而不依赖于标准库或者第三方库。

复数由实部(real)和虚部(imag)构成,在 Python 中,复数的虚部以j或者J作为后缀,具体格式为:

1
>a + bj

a 表示实部,b 表示虚部。

代码案例:

1
2
3
4
5
6
7
8
9
10
>c1 = 12 + 0.2j
>print("c1Value: ", c1)
>print("c1Type", type(c1))

>c2 = 6 - 1.2j
>print("c2Value: ", c2)

>#对复数进行简单计算
>print("c1+c2: ", c1+c2)
>print("c1*c2: ", c1*c2)

运行结果:

1
2
3
4
5
>c1Value:  (12+0.2j)
c1Type <class 'complex'>
c2Value: (6-1.2j)
c1+c2: (18-1j)
c1*c2: (72.24-13.2j)

可以发现,复数在 Python 内部的类型是 complex,Python 默认支持对复数的简单计算。

字符串(String)

​ 若干个字符的集合就是一个字符串(String)。Python中的字符串必须由双引号" "或者单引号' '包围,具体格式为:

1
2
>"字符串内容"
>'字符串内容'
处理字符串中的引号

​ 当字符串内容中出现引号时,我们需要进行特殊处理,否则 Python 会解析出错,例如:

1
>'I'm a great coder!'

由于上面字符串中包含了单引号,此时 Python 会将字符串中的单引号与第一个单引号配对,这样就会把'I'当成字符串,而后面的m a great coder!'就变成了多余的内容,从而导致语法错误。

​ 对于这种情况,有两种处理方案:

1.对引号进行转义

​ 在引号前面添加反斜杠\就可以对引号进行转义,让 Python 把它作为普通文本对待,例如:

1
2
3
4
>>str1 = 'I\'m a great coder!'
>>str2 = "引文双引号是\",中文双引号是“"
>>print(str1)
>>print(str2)

运行结果:

1
2
>>I'm a great coder!
>>引文双引号是",中文双引号是“

2.使用不同的引号包围字符串

​ 如果字符串内容中出现了单引号,那么我们可以使用双引号包围字符串,反之亦然。例如:

1
2
3
4
>>str1 = "I'm a great coder!"  #使用双引号包围含有单引号的字符串
>>str2 = '引文双引号是",中文双引号是“' #使用单引号包围含有双引号的字符串
>>print(str1)
>>print(str2)

运行结果和上面相同。

处理字符串中的换行

Python 不是格式自由的语言,它对程序的换行、缩进都有严格的语法要求。要想换行书写一个比较长的字符串,必须在行尾添加反斜杠\,请看下面的例子:

1
2
3
>s2 = 'It took me six months to write this Python tutorial. \
Please give me more support. \
I will keep it updated.'

上面 s2 字符串的比较长,所以使用了转义字符\对字符串内容进行了换行,这样就可以把一个长字符串写成多行。

​ 另外,Python 也支持表达式的换行,例如:

1
2
3
>num = 20 + 3 / 4 + \
2 * 3
>print(num)
长字符串

在Python注释中,使用三个单引号或者双引号可以对多行内容进行注释,这其实是 Python 长字符串的写法。所谓长字符串,就是可以直接换行(不用加反斜杠\)书写的字符串。

​ Python 长字符串由三个双引号"""或者三个单引号'''包围,语法格式如下:

1
2
>"""长字符串内容"""
'''长字符串内容'''

在长字符串中放置单引号或者双引号不会导致解析错误。

如果长字符串没有赋值给任何变量,那么这个长字符串就不会起到任何作用,和一段普通的文本无异,相当于被注释掉了。

​ 长字符串中的换行、空格、缩进等空白符都会原样输出,所以你不能写成下面的样子:

1
2
3
4
5
6
>longstr = '''
It took me 6 months to write this Python tutorial.
Please give me a to 'thumb' to keep it updated.
The Python tutorial is available at http://os-guangchuang.gitee.io/note.
>'''
>print(longstr)

虽然这样写格式优美,但是输出结果将变成:

1
2
3
4

It took me 6 months to write this Python tutorial.
Please give me a to 'thumb' to keep it updated.
The Python tutorial is available at http://os-guangchuang.gitee.io/note.

字符串内容前后多出了两个空行,并且每一行的前面会多出四个空格。

原始字符串

​ Python 字符串中的反斜杠\有着特殊的作用,就是转义字符,例如上面提到的\'\".

​ 转义字符有时候会带来一些麻烦,例如我要表示一个包含 Windows 路径D:\Program Files\Python 3.8\python.exe这样的字符串,在 Python 程序中直接这样写肯定是不行的,不管是普通字符串还是长字符串。因为\的特殊性,我们需要对字符串中的每个\都进行转义,也就是写成D:\\Program Files\\Python 3.8\\python.exe这种形式才行。

​ 这种写法需要特别谨慎,稍有疏忽就会出错。为了解决转义字符的问题,Python 支持原始字符串。在原始字符串中,\不会被当作转义字符,所有的内容都保持“原汁原味”的样子。

​ 在普通字符串或者长字符串的开头加上r前缀,就变成了原始字符串,具体格式为:

​ 将上面的 Windows 路径改写成原始字符串的形式:

1
2
>rstr = r'D:\Program Files\Python 3.8\python.exe'
>print(rstr)

原始字符串中引号

如果普通格式的原始字符串中出现引号,程序同样需要对引号进行转义,否则 Python 照样无法对字符串的引号精确配对;但是和普通字符串不同的是,此时用于转义的反斜杠会变成字符串内容的一部分。

请看下面的代码:

1
2
>str1 = r'I\'m a great coder!'
>print(str1)

输出结果:

1
>I\'m a great coder!

需要注意的是,Python 原始字符串中的反斜杠仍然会对引号进行转义,因此原始字符串的结尾处不能是反斜杠,否则字符串结尾处的引号会被转义,导致字符串不能正确结束。

在 Python 中有两种方式解决这个问题:一种方式是改用长字符串的写法,不要使用原始字符串;另一种方式是单独书写反斜杠,这是接下来要重点说明的。

​ 例如想表示D:\Program Files\Python 3.8\,可以这样写:

1
2
>str1 = r'D:\Program Files\Python 3.8' '\\'
>print(str1)

我们先写了一个原始字符串r'D:\Program Files\Python 3.8',紧接着又使用'\\'写了一个包含转义字符的普通字符串,Python 会自动将这两个字符串拼接在一起,所以上面代码的输出结果是:

1
>D:\Program Files\Python 3.8\

字节串类型(bytes)

Python bytes 类型用来表示一个字节串。“字节串“不是编程术语,是我自己“捏造”的一个词,用来和字符串相呼应。

bytes 是 Python 3.x 新增的类型,在 Python 2.x 中是不存在的。

字节串(bytes)和字符串(string)的对比:

  • 字符串由若干个字符组成,以字符为单位进行操作;字节串由若干个字节组成,以字节为单位进行操作。
  • 字节串和字符串除了操作的数据单元不同之外,它们支持的所有方法都基本相同。
  • 字节串和字符串都是不可变序列,不能随意增加和删除数据。

bytes 只负责以字节序列的形式(二进制形式)来存储数据,至于这些数据到底表示什么内容(字符串、数字、图片、音频等),完全由程序的解析方式决定。如果采用合适的字符编码方式(字符集),字节串可以恢复成字符串;反之亦然,字符串也可以转换成字节串。

说白了,bytes 只是简单地记录内存中的原始数据,至于如何使用这些数据,bytes 并不在意,你想怎么使用就怎么使用,bytes 并不约束你的行为。

bytes 类型的数据非常适合在互联网上传输,可以用于网络通信编程;bytes 也可以用来存储图片、音频、视频等二进制格式的文件。

字符串和 bytes 存在着千丝万缕的联系,我们可以通过字符串来创建 bytes 对象,或者说将字符串转换成 bytes 对象。有以下三种方法可以达到这个目的:

  • 如果字符串的内容都是 ASCII 字符,那么直接在字符串前面添加b前缀就可以转换成 bytes。
  • bytes 是一个类,调用它的构造方法,也就是 bytes(),可以将字符串按照指定的字符集转换成 bytes;如果不指定字符集,那么默认采用 UTF-8。
  • 字符串本身有一个 encode() 方法,该方法专门用来将字符串按照指定的字符集转换成对应的字节串;如果不指定字符集,那么默认采用 UTF-8。

实例:使用不同方式创建bytes对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>#通过构造函数创建空 bytes
>b1 = bytes()
>#通过空字符串创建空 bytes
>b2 = b''

>#通过b前缀将字符串转换成 bytes
>b3 = b'http://os-guangchuang.gitee.io/note/'
>print("b3: ", b3)
>print(b3[3])
>print(b3[7:22])

>#为 bytes() 方法指定字符集
>b4 = bytes('我爱编程', encoding='UTF-8')
>print("b4: ", b4)

>#通过 encode() 方法将字符串转换成 bytes
>b5 = "我爱编程".encode('UTF-8')
>print("b5: ", b5)

从运行结果可以发现,对于非 ASCII 字符,print 输出的是它的字符编码值(十六进制形式),而不是字符本身。非 ASCII 字符一般占用两个字节以上的内存,而 bytes 是按照单个字节来处理数据的,所以不能一次处理多个字节。

​ bytes 类也有一个 decode() 方法,通过该方法可以将 bytes 对象转换为字符串。紧接上面的程序,添加以下代码:

1
2
3
>#通过 decode() 方法将 bytes 转换成字符串
>str1 = b5.decode('UTF-8')
>print("str1: ", str1)

运行结果:

1
>str1:我爱编程

布尔类型(bool)

Python 提供了 bool 类型来表示真(对)或假(错),比如常见的5 > 3比较算式,这个是正确的,在程序世界里称之为真(对),Python 使用 True 来代表;再比如4 > 20比较算式,这个是错误的,在程序世界里称之为假(错),Python 使用 False 来代表。

True 和 False 是 Python 中的关键字,当作为 Python 代码输入时,一定要注意字母的大小写,否则解释器会报错。

值得一提的是,布尔类型可以当做整数来对待,即 True 相当于整数值 1,False 相当于整数值 0。因此,下边这些运算都是可以的:

1
2
3
4
>>>> False+1
1
>>> True+1
2

注意,这里只是为了说明 True 和 Flase 对应的整型值,在实际应用中是不妥的,不要这么用。

总的来说,bool 类型就是用于代表某个事情的真(对)或假(错),如果这个事情是正确的,用 True(或 1)代表;如果这个事情是错误的,用 False(或 0)代表。

1
2
3
4
>>>> 5>3
True
>>> 4>20
False

数据输入

input() 是 Python 的内置函数,用于从控制台读取用户输入的内容。input() 函数总是以字符串的形式来处理用户输入的内容,所以用户输入的内容可以包含任何字符。

input() 函数的用法为:

1
>str = input(tipmsg)

说明:

  • str 表示一个字符串类型的变量,input 会将读取到的字符串放入 str 中。
  • tipmsg 表示提示信息,它会显示在控制台上,告诉用户应该输入什么样的内容;如果不写 tipmsg,就不会有任何提示信息。

实例: input() 函数的简单使用:

1
2
3
4
5
6
7
8
9
>a = input("Enter a number: ")
>b = input("Enter another number: ")

>print("aType: ", type(a))
>print("bType: ", type(b))

>result = a + b
>print("resultValue: ", result)
>print("resultType: ", type(result))

运行结果:

1
2
3
4
5
6
>Enter a number: 100
Enter another number: 45
aType: <class 'str'>
bType: <class 'str'>
resultValue: 10045
resultType: <class 'str'>

表示按下回车键,按下回车键后 input() 读取就结束了。

​ 本例中我们输入了两个整数,希望计算出它们的和,但是事与愿违,Python 只是它们当成了字符串,+起到了拼接字符串的作用,而不是求和的作用。

​ 我们可以使用 Python 内置函数将字符串转换成想要的类型,比如:

  • int(string) 将字符串转换成 int 类型;
  • float(string) 将字符串转换成 float 类型;
  • bool(string) 将字符串转换成 bool 类型。

修改上面的代码,将用户输入的内容转换成数字:

1
2
3
4
5
6
7
8
9
10
>a = input("Enter a number: ")
>b = input("Enter another number: ")
>a = float(a)
>b = int(b)
>print("aType: ", type(a))
>print("bType: ", type(b))

>result = a + b
>print("resultValue: ", result)
>print("resultType: ", type(result))

运行结果:

1
2
3
4
5
6
>Enter a number: 12.5
Enter another number: 64
aType: <class 'float'>
bType: <class 'int'>
resultValue: 76.5
resultType: <class 'float'>

数据类型转换

虽然 Python 是弱类型编程语言,不需要像 Java 或 C 语言那样还要在使用变量前声明变量的类型,但在一些特定场景中,仍然需要用到类型转换。

比如说,我们想通过使用 print() 函数输出信息“您的身高:”以及浮点类型 height 的值,如果在交互式解释器中执行如下代码:

1
2
3
4
5
6
>>>> height = 70.0
>>> print("您的身高"+height)
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
print("您的身高"+height)
TypeError: must be str, not float

你会发现这是错误的,解释器提示我们字符串和浮点类型变量不能直接相连,需要提前将浮点类型变量 height 转换为字符串才可以。

庆幸的是,Python 已经为我们提供了多种可实现数据类型转换的函数,如表 1 所示。

需要注意的是,在使用类型转换函数时,提供给它的数据必须是有意义的。例如,int() 函数无法将一个非数字字符串转换成整数:

1
2
3
4
5
6
7
8
>>>> int("123") #转换成功
>123
>>> int("123个") #转换失败
>Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
int("123个")
>ValueError: invalid literal for int() with base 10: '123个'
>>>

运算符

算术运算符

算术运算符也即数学运算符,用来对数字进行数学运算,比如加减乘除。下表列出了 Python 支持所有基本算术运算符。

加法运算符:+

实例1:数字相加

加法运算符很简单,和数学中的规则一样,请看下面的代码:

1
2
3
4
5
6
7
8
9
>>m = 10
>>n = 97
>>sum1 = m + n

>>x = 7.2
>>y = 15.3
>>sum2 = x + y

>>print("sum1=%d, sum2=%.2f" % (sum1, sum2) )

运行结果: sum1=107, sum2=22.50

实例2:连接字符串

1
2
3
4
5
>>name="张三"
>>age=18
>>info="姓名:"+name+",年龄:"+str(age)

>>print(info);

运行结果:姓名:张三,年龄:18

减法运算符:-

实例1: 减法运算也和数学中的规则相同,请看代码:

1
2
3
4
5
6
7
>>n = 45
>>m = -n

>>x = -83.5
>>y = -x

>>print(m, ",", y)

运行结果: -45 , 83.5

乘法运算符:*

实例1: 乘法运算也和数学中的规则相同,请看代码:

1
2
3
>>n = 4 * 25
>>f = 34.5 * 2
>>print(n, ",", f)

运行结果: 运行结果: 100 , 69.0

实例2:重复字符串

1
2
>>str1 = "hello "
>>print(str1 * 4)

运行结果: hello hello hello hello 

除法运算符:/和//

Python 支持///两个除法运算符,但它们之间是有区别的:

  • /表示普通除法,使用它计算出来的结果和数学中的计算结果相同。
  • //表示整除,只保留结果的整数部分,舍弃小数部分;注意是直接丢掉小数部分,而不是四舍五入。

实例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>#整数不能除尽
>>print("23/5 =", 23/5)
>>print("23//5 =", 23//5)
>>print("23.0//5 =", 23.0//5)
>>print("-------------------")

>>#整数能除尽
>>print("25/5 =", 25/5)
>>print("25//5 =", 25//5)
>>print("25.0//5 =", 25.0//5)
>>print("-------------------")

>>#小数除法
>>print("12.4/3.5 =", 12.4/3.5)
>>print("12.4//3.5 =", 12.4//3.5)

运行结果:

1
2
3
4
5
6
7
8
9
10
>>23/5 = 4.6
23//5 = 4
23.0//5 = 4.0
-------------------
25/5 = 5.0
25//5 = 5
25.0//5 = 5.0
-------------------
12.4/3.5 = 3.542857142857143
12.4//3.5 = 3.0

从运行结果可以发现:

  • /的计算结果总是小数,不管是否能除尽,也不管参与运算的是整数还是小数。
  • 当有小数参与运算时,//结果才是小数,否则就是整数。

取余运算符:%

Python % 运算符用来求得两个数相除的余数,包括整数和小数。Python 使用第一个数字除以第二个数字,得到一个整数的商,剩下的值就是余数。对于小数,求余的结果一般也是小数。

实例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>print("-----整数求余-----")
>>print("15%6 =", 15%6)
>>print("-15%6 =", -15%6)
>>print("15%-6 =", 15%-6)
>>print("-15%-6 =", -15%-6)

>>print("-----小数求余-----")
>>print("7.7%2.2 =", 7.7%2.2)
>>print("-7.7%2.2 =", -7.7%2.2)
>>print("7.7%-2.2 =", 7.7%-2.2)
>>print("-7.7%-2.2 =", -7.7%-2.2)

>>print("---整数和小数运算---")
>>print("23.5%6 =", 23.5%6)
>>print("23%6.5 =", 23%6.5)
>>print("23.5%-6 =", 23.5%-6)
>>print("-23%6.5 =", -23%6.5)
>>print("-23%-6.5 =", -23%-6.5)

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>-----整数求余-----
>>15%6 = 3
-15%6 = 3
15%-6 = -3
-15%-6 = -3
>>-----小数求余-----
>>7.7%2.2 = 1.0999999999999996
-7.7%2.2 = 1.1000000000000005
7.7%-2.2 = -1.1000000000000005
-7.7%-2.2 = -1.0999999999999996
>>---整数和小数运算---
>>23.5%6 = 5.5
23%6.5 = 3.5
23.5%-6 = -0.5
-23%6.5 = 3.0
-23%-6.5 = -3.5

从运行结果可以发现两点:

  • 只有当第二个数字是负数时,求余的结果才是负数。换句话说,求余结果的正负和第一个数字没有关系,只由第二个数字决定。
  • %两边的数字都是整数时,求余的结果也是整数;但是只要有一个数字是小数,求余的结果就是小数。

乘方运算符:**

Python ** 运算符用来求一个 x 的 y 次方,也即次方(乘方)运算符。

由于开方是次方的逆运算,所以也可以使用 ** 运算符间接地实现开方运算。

1
2
3
4
5
6
7
>>print('----次方运算----')
>>print('3**4 =', 3**4)
>>print('2**5 =', 2**5)

>>print('----开方运算----')
>>print('81**(1/4) =', 81**(1/4))
>>print('32**(1/5) =', 32**(1/5))

运行结果:

1
2
3
4
5
6
>>----次方运算----
>>3**4 = 81
>>2**5 = 32
>>----开方运算----
>>81**(1/4) = 3.0
>>32**(1/5) = 2.0

比较运算符

比较运算符,也称关系运算符,用于对常量、变量或表达式的结果进行大小比较。如果这种比较是成立的,则返回 True(真),反之则返回 False(假)。

Python 支持的比较运算符如表 1 所示。

Python 比较运算符的使用举例:

1
2
3
4
5
6
7
>print("89是否大于100:", 89 > 100)
>print("24*5是否大于等于76:", 24*5 >= 76)
>print("86.5是否等于86.5:", 86.5 == 86.5)
>print("34是否等于34.0:", 34 == 34.0)
>print("False是否小于True:", False < True)
>print("True是否等于True:", True == True)

运行结果:

1
2
3
4
5
6
7
>89是否大于100: False
24*5是否大于等于76: True
86.5是否等于86.5: True
34是否等于34.0: True
False是否小于True: True
True是否等于True: False

代码案例:

1
2
3
4
5
6
7
8
9
10
>#定义变量
>num1=5
>num2=int(input("请输入一个整数:"))

>#计算
>result=num1>num2

>#输出
>print("result:",result)
>print("result type:",type(result))

代码案例:

1
2
3
4
5
6
7
8
9
10
11
>#定义变量
>num1=5
>num2=int(input("请输入一个整数:"))

>#输出结果
>print("num1>num2:",num1>num2)
>print("num1>=num2:",num1>=num2)
>print("num1<num2:",num1<num2)
>print("num1<=num2:",num1<=num2)
>print("num1==num2:",num1==num2)
>print("num1!=num2:",num1!=num2)

== 和 is的区别:

初学 Python,大家可能对 is 比较陌生,很多人会误将它和 == 的功能混为一谈,但其实 is 与 == 有本质上的区别,完全不是一码事儿。

== 用来比较两个变量的值是否相等,而 is 则用来比对两个变量引用的是否是同一个对象,例如:

1
2
3
4
5
6
7
>>import time  #引入time模块

>>t1 = time.gmtime() # gmtime()用来获取当前时间
>>t2 = time.gmtime()

>>print(t1 == t2) #输出True
>>print(t1 is t2) #输出False

运行结果:

1
2
>>True
>>False

time 模块的 gmtime() 方法用来获取当前的系统时间,精确到秒级,因为程序运行非常快,所以 t1 和 t1 得到的时间是一样的。== 用来判断 t1 和 t2 的值是否相等,所以返回 True。

虽然 t1 和 t2 的值相等,但它们是两个不同的对象(每次调用 gmtime() 都返回不同的对象),所以t1 is t2返回 False。这就好像两个双胞胎姐妹,虽然她们的外貌是一样的,但它们是两个人。

逻辑运算符

高中数学中我们就学过逻辑运算,例如 p 为真命题,q 为假命题,那么“p且q”为假,“p或q”为真,“非q”为真。Python 也有类似的逻辑运算,请看下表:

逻辑运算符一般和关系运算符结合使用,例如:

1
>14>6 and 45.6 > 90

14>6 结果为 True,成立,45.6>90 结果为 False,不成立,所以整个表达式的结果为 False,也即不成立。

再看一个比较实用的例子:

1
2
3
4
5
6
7
>age = int(input("请输入年龄:"))
>height = int(input("请输入身高:"))

>if age>=18 and age<=30 and height >=170 and height <= 185 :
print("恭喜,你符合报考飞行员的条件")
>else:
print("抱歉,你不符合报考飞行员的条件")

可能的运行结果:

1
2
3
>请输入年龄:23↙
>请输入身高:178↙
>恭喜,你符合报考飞行员的条件

代码案例:

1
2
3
4
5
6
7
8
9
>#定义变量
>num1=int(input("请输入第一个整数:"))
>num2=int(input("请输入第二个整数:"))
>num3=int(input("请输入第三个整数:"))

>#计算并输出
>print("num1>num2 && num2>num3:",num1>num2 and num2>num3)
>print("num1>num2 or num2>num3:",num1>num2 or num2>num3)
>print("not num1>num2:",not num1>num2)

重要特点

Python 逻辑运算符可以用来操作任何类型的表达式,不管表达式是不是 bool 类型;同时,逻辑运算的结果也不一定是 bool 类型,它也可以是任意类型。请看下面的例子:

1
2
3
4
>>print(100 and 200)
>>print(45 and 0)
>>print("" or "https://os-guangchuang.gitee.io/note/")
>>print(18.5 or "https://os-guangchuang.gitee.io/note/")

运行结果:

逻辑运算符的本质

在 Python 中,and 和 or 不一定会计算右边表达式的值,有时候只计算左边表达式的值就能得到最终结果。

另外,and 和 or 运算符会将其中一个表达式的值作为最终结果,而不是将 True 或者 False 作为最终结果。

以上两点极其重要,了解这两点不会让你在使用逻辑运算的过程中产生疑惑。

对于 and 运算符,两边的值都为真时最终结果才为真,但是只要其中有一个值为假,那么最终结果就是假,所以 Python 按照下面的规则执行 and 运算:

第一种情况(判断语句):

从右往左解析,只要第一个是False,就是False,后面的就不需要运算了,整个都是错误的,无论后面是正确还是错误。记住一句话所有的判断语句除非都为True,整个句子为True,但凡有一个为False,整个都是False。

1
2
3
4
5
>print (1 > 2 and 0 < 1)#False
>print (1 > 2 and 0 > 1) #False
>print (1 < 2 and 0 < 1)#True
>print (1 > 2 and 0 < 1)#False
>print (1 > 2 and 0 < 1 and 2 > 0 and 5 > 1) #False

第二种情况(都为数字时):

从右往左解析,0为False,1为True。同理,记住一句话语句中没有0整个句子就为True,但凡有一个为0,整个都是句子就为0。

1
2
3
4
5
6
>print (0 and 5) #0
>print (1 and 5) #5
>print (5 and 0) #0
>print (10 and 0 and 5 and 0)#0
>print (6 and 4 and 3)#3
>print (1 and 4 and 2 and 6) #6
  • 如果左边表达式的值为假,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是假,此时 and 会把左边表达式的值作为最终结果。
  • 如果左边表达式的值为真,那么最终值是不能确定的,and 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。

对于 or 运算符,情况是类似的,两边的值都为假时最终结果才为假,只要其中有一个值为真,那么最终结果就是真,所以 Python 按照下面的规则执行 or 运算:

第一种情况(判断语句):

从左往右解析,依次看语句是否为True,如果为True,整条语句都为True;不是的话,看下一条语句,同理,若都不是整条语句为False。

1
2
3
4
>print (1 > 2 or 0 < 1) #True
>print (1 < 2 or 0 > 1) #True
>print (1 > 2 or 0 > 1) #False
>print (1 < 2 or 0 > 1 or 2 > 3)#True

第二种情况(都为数字时):

从左往右依次解析,找到0了,看下一个数。不是0的话,整条语句就是不是0的那个值。

1
2
3
4
5
>print (0 or 10) #10
>print (1 or 2) #1
>print (1 or 0) #1
>print (7 or 5 or 5)#7
>print (9 or 5 or 6 or 0 or 8)#9
  • 如果左边表达式的值为真,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是真,此时 or 会把左边表达式的值作为最终结果。
  • 如果左边表达式的值为假,那么最终值是不能确定的,or 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。

三目运算符

对于基本if判断, Python提供了一种更加简洁的写法,如下所示:

1
>max = a if a>b else b

这是一种类似于其它编程语言中三目运算符? :的写法。Python 是一种极简主义的编程语言,它没有引入? :这个新的运算符,而是使用已有的 if else 关键字来实现相同的功能。

使用 if else 实现三目运算符(条件运算符)的格式如下:

1
>exp1 if contion else exp2

condition 是判断条件,exp1 和 exp2 是两个表达式。如果 condition 成立(结果为真),就执行 exp1,并把 exp1 的结果作为整个表达式的结果;如果 condition 不成立(结果为假),就执行 exp2,并把 exp2 的结果作为整个表达式的结果。

前面的语句max = a if a>b else b的含义是:

  • 如果 a>b 成立,就把 a 作为整个表达式的值,并赋给变量 max;
  • 如果 a> b 不成立,就把 b 作为整个表达式的值,并赋给变量 max。

三目运算符的嵌套:

Python 三目运算符支持嵌套,如此可以构成更加复杂的表达式。在嵌套时需要注意 if 和 else 的配对,例如:

1
>a if a>b else c if c>d else d

可以理解为:

1
>a if a>b else ( c if c>d else d )

使用 Python 三目运算符判断两个数字的关系:

1
2
3
>a = int( input("Input a: ") )
>b = int( input("Input b: ") )
>print("a大于b") if a>b else ( print("a小于b") if a<b else print("a等于b") )

可能的运行结果:

1
2
3
>Input a: 45
>Input b: 100
>a小于b

该程序是一个嵌套的三目运算符。程序先对 a>b 求值,如果该表达式为 True,程序就返回执行第一个表达式 print(“a大于b”),否则将继续执行 else 后面的内容,也就是:

1
>( print("a小于b") if a<b else print("a等于b") )

进入该表达式后,先判断 a<b 是否成立,如果 a<b 的结果为 True,将执行 print(“a小于b”),否则执行 print(“a等于b”)。

位运算符

Python 位运算按照数据在内存中的二进制位(Bit)进行操作,它一般用于底层开发(算法设计、驱动、图像处理、单片机等),在应用层开发(Web 开发、Linux 运维等)中并不常见。想加快学习进度,或者不关注底层开发的读者可以先跳过本节,以后需要的话再来学习。

Python 位运算符只能用来操作整数类型,它按照整数在内存中的二进制形式进行计算。Python 支持的位运算符如表 1 所示。

按位与运算 &

按位与运算符&的运算规则是:只有参与&运算的两个位都为 1 时,结果才为 1,否则为 0。例如1&1为 1,0&0为 0,1&0也为 0,这和逻辑运算符&&非常类似。

例如,9&5可以转换成如下的运算:

1
2
3
4
5
  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 (5 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0001 (1 在内存中的存储)

&运算符会对参与运算的两个整数的所有二进制位进行&运算,9&5的结果为 1。

又如,-9&5可以转换成如下的运算:

1
2
3
4
5
  1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 (5 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 (5 在内存中的存储)

-9&5的结果是 5。

按位或运算 |

按位或运算符|的运算规则是:两个二进制位有一个为 1 时,结果就为 1,两个都为 0 时结果才为 0。例如1|1为 1,0|0为0,1|0 为1,这和逻辑运算中的||非常类似。

例如,9 | 5可以转换成如下的运算:

1
2
3
4
5
  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
| 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 (5 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1101 (13 在内存中的存储)

9 | 5的结果为 13。

又如,-9 | 5可以转换成如下的运算:

1
2
3
4
5
  1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
| 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 (5 在内存中的存储)
-----------------------------------------------------------------------------------
1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111 (-9 在内存中的存储)

-9 | 5的结果是 -9。

按位异或运算 ^

按位异或运算^的运算规则是:参与运算的两个二进制位不同时,结果为 1,相同时结果为 0。例如0^1为 1,0^0为 0,1^1为 0。

例如,9 ^ 5可以转换成如下的运算:

1
2
3
4
5
  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
^ 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 (5 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1100 (12 在内存中的存储)

9 ^ 5的结果为 12。

又如,-9 ^ 5可以转换成如下的运算:

1
2
3
4
5
  1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
^ 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101 (5 在内存中的存储)
-----------------------------------------------------------------------------------
1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0010 (-14 在内存中的存储)

按位取反 ~

按位取反运算符~为单目运算符(只有一个操作数),右结合性,作用是对参与运算的二进制位取反。例如~1为0,~0为1,这和逻辑运算中的!非常类似。

例如,~9可以转换为如下的运算:

1
2
3
4
~ 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
-----------------------------------------------------------------------------------
1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0110 (-10 在内存中的存储)

所以~9的结果为 -10。

例如,~-9可以转换为如下的运算:

1
2
3
4
~ 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1000 (8 在内存中的存储)

所以~-9的结果为 8。

按位左移

Python 左移运算符<<用来把操作数的各个二进制位全部左移若干位,高位丢弃,低位补 0。

例如,9<<3可以转换为如下的运算:

1
2
3
4
<< 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0100 1000 (72 在内存中的存储)

所以9<<3的结果为 72。

又如,(-9)<<3可以转换为如下的运算:

1
2
3
4
<< 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-----------------------------------------------------------------------------------
1111 1111 -- 1111 1111 -- 1111 1111 -- 1011 1000 (-72 在内存中的存储)

所以(-9)<<3的结果为 -72

如果数据较小,被丢弃的高位不包含 1,那么左移 n 位相当于乘以 2 的 n 次方。

使用 Python 代码对上面的分析进行验证:

1
2
print("%X" % (9<<3) )
print("%X" % ((-9)<<3) )

运行结果:

48

-48

按位右移

Python 右移运算符>>用来把操作数的各个二进制位全部右移若干位,低位丢弃,高位补 0 或 1。如果数据的最高位是 0,那么就补 0;如果最高位是 1,那么就补 1。

例如,9>>3可以转换为如下的运算:

1
2
3
4
>> 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
-----------------------------------------------------------------------------------
0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0001 (1 在内存中的存储)

所以9>>3的结果为 1。

又如,(-9)>>3可以转换为如下的运算:

1
2
3
4
>> 1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-----------------------------------------------------------------------------------
1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 1110 (-2 在内存中的存储)

所以(-9)>>3的结果为 -2

如果被丢弃的低位不包含 1,那么右移 n 位相当于除以 2 的 n 次方(但被移除的位中经常会包含 1)。

使用 Python 代码对上面的分析进行验证:

1
2
print("%X" % (9>>3) )
print("%X" % ((-9)>>3) )

运行结果:

1

-2

赋值运算符

赋值运算符用来把右侧的值传递给左侧的变量(或者常量);可以直接将右侧的值交给左侧的变量,也可以进行某些运算后再交给左侧的变量,比如加减乘除、函数调用、逻辑运算等。

Python 中最基本的赋值运算符是等号=;结合其它运算符,=还能扩展出更强大的赋值运算符。

基本赋值运算符

=是 Python 中最常见、最基本的赋值运算符,用来将一个表达式的值赋给另一个变量,请看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#将字面量(直接量)赋值给变量
n1 = 100
f1 = 47.5
s1 = "http://c.biancheng.net/python/"

#将一个变量的值赋给另一个变量
n2 = n1
f2 = f1

#将某些运算的值赋给变量
sum1 = 25 + 46
sum2 = n1 % 6
s2 = str(1234) #将数字转换成字符串
s3 = str(100) + "abc"

连续赋值:

Python 中的赋值表达式也是有值的,它的值就是被赋的那个值,或者说是左侧变量的值;如果将赋值表达式的值再赋值给另外一个变量,这就构成了连续赋值。请看下面的例子:

1
a = b = c = 100

=具有右结合性,我们从右到左分析这个表达式:

  • c = 100 表示将 100 赋值给 c,所以 c 的值是 100;同时,c = 100 这个子表达式的值也是 100。
  • b = c = 100 表示将 c = 100 的值赋给 b,因此 b 的值也是 100。
  • 以此类推,a 的值也是 100。

扩展后的赋值运算符

=还可与其他运算符(包括算术运算符、位运算符和逻辑运算符)相结合,扩展成为功能更加强大的赋值运算符,如表 1 所示。扩展后的赋值运算符将使得赋值表达式的书写更加优雅和方便。

代码案例:

1
2
3
4
5
6
7
8
n1 = 100
f1 = 25.5

n1 -= 80 #等价于 n1=n1-80
f1 *= n1 - 10 #等价于 f1=f1*( n1 - 10 )

print("n1=%d" % n1)
print("f1=%.2f" % f1)

运行结果为:

n1=20

f1=255.00

但是请注意,这种赋值运算符只能针对已经存在的变量赋值,因为赋值过程中需要变量本身参与运算,如果变量没有提前定义,它的值就是未知的,无法参与运算。

运算符的优先级

所谓优先级,就是当多个运算符同时出现在一个表达式中时,先执行哪个运算符。

例如对于表达式a + b * c,Python 会先计算乘法再计算加法;b * c的结果为 8,a + 8的结果为 24,所以 d 最终的值也是 24。先计算*再计算+,说明*的优先级高于+

Python 支持几十种运算符,被划分成将近二十个优先级,有的运算符优先级不同,有的运算符优先级相同,请看下表。

结果表1中的运算符优先级,我们尝试分析下面表达式的结果:

1
>4+4<<2

+的优先级是 12,<<的优先级是 11,+的优先级高于<<,所以先执行 4+4,得到结果 8,再执行 8<<2,得到结果 32,这也是整个表达式的最终结果。

像这种不好确定优先级的表达式,我们可以给子表达式加上( ),也就是写成下面的样子:

1
>(4+4) << 2

这样看起来就一目了然了,不容易引起误解。 当然,我们也可以使用( )改变程序的执行顺序,比如:

1
>4+(4<<2)

则先执行 4<<2,得到结果 16,再执行 4+16,得到结果20。

虽然 Python 运算符存在优先级的关系,但我不推荐过度依赖运算符的优先级,这会导致程序的可读性降低。因此,我建议读者:

  • 不要把一个表达式写得过于复杂,如果一个表达式过于复杂,可以尝试把它拆分来书写。
  • 不要过多地依赖运算符的优先级来控制表达式的执行顺序,这样可读性太差,应尽量使用( )来控制表达式的执行顺序。

python运算符的结合性

所谓结合性,就是当一个表达式中出现多个优先级相同的运算符时,先执行哪个运算符:先执行左边的叫左结合性,先执行右边的叫右结合性。

例如对于表达式对于100 / 25 * 16/*的优先级相同,应该先执行哪一个呢?这个时候就不能只依赖运算符优先级决定了,还要参考运算符的结合性。/*都具有左结合性,因此先执行左边的除法,再执行右边的乘法,最终结果是 64。

Python 中大部分运算符都具有左结合性,也就是从左到右执行;只有 ** 乘方运算符、单目运算符(例如 not 逻辑非运算符)、赋值运算符和三目运算符例外,它们具有右结合性,也就是从右向左执行。表 1 中列出了所有 Python 运算符的结合性。

当一个表达式中出现多个运算符时,Python 会先比较各个运算符的优先级,按照优先级从高到低的顺序依次执行;当遇到优先级相同的运算符时,再根据结合性决定先执行哪个运算符:如果是左结合性就先执行左边的运算符,如果是右结合性就先执行右边的运算符。

课后作业