1.1 自学
必须⾃学 ⾃学,是成为⼀名优秀程序员的唯⼀途径,注意不是“途径之⼀”,⽽是“唯⼀途径”,舍此⽆ 他。 有幸遇到过很多优秀程序员,曾向他们请教有关个⼈发展的问题。这些青年才俊,毫⽆例外 都谈到了“⾃学”。⽤不完全归纳法,可以认为优秀程序是“⾃学成才”的,或者说具有较强的 ⾃学能⼒。虽然此结论没有得到严格的证明,但它是多年的经验积累——⼈⽣经验不同于数 学定理,通常难以证明。诚然,如果不认可,亦不能强求。
1.2 操作系统
1.2.1 windows的DMS命令
命令 说明 MD 创建⼦⽬录 CD 改变当前⽬录,进⼊到指定的⽬录
DIR 显⽰指定位置下的⽬录和⽂件(默认是当前位置) TREE 显⽰⽬录结构
COPY 复制⽂件 REN ⽂件改名命令
DEL 刪除⽂件命令 DATE 查看⽇期命令
在 Windows 中输⼊命令,不区分⼤⼩写.
建议去看windows下的DOS命令
1.2.2 LINUX操作系统
Linux 是⼀种开源操作系统,它以 Unix 为基础,发明⼈是 Linus Torvalds(如图1-5-7所 ⽰)。这是⼀位令众多程序员膜拜的、为 IT 业做出卓越贡献的开发者,他除了发明 Linux 操作系统之外,还发明了⼀种源码管理系统 Git ,是⽬前⼴泛应⽤的源码管理⼯具。
命令 说明 mkdir 创建⼦⽬录 cd 改变当前⽬录,进⼊到指定的⽬录
ls 显⽰指定位置下的⽬录和⽂件(默认是当前位置) cp 复制⽂件
rm 刪除⽂件命令 cat 在显⽰器上查看⽂件内容
mv 移动⽂件或⽬录,还可以对其重命名
find 在给定位置按照条件进⾏搜索 shutdown 关闭计算机
现在⽤的计算机是 Windows 操作系统,建议从以下⽅式中选择⼀种,在⾃ ⼰的计算机上安装 Ubuntu 操作系统,并⼒争将其作为开发和学习的主要环境,⾄少 要有所体验。 ⽅式1:卸载 Windows 操作系统后安装 Ubuntu 系统。特别是针对“⽼旧”计算机,运 ⾏ Windows 系统及应⽤软件,已经“慢吞吞”了,如果改为 Ubuntu 系统,⽴刻会实 现“飞⼀般”的操作。除了卸载原有 Windows 操作系统之外,还可以在性能较好的计 算机上安装双系统,开机时选择将要使⽤的操作系统。具体安装⽅法请参阅 Ubuntu 官⽅⽹站的安装指南(https://ubuntu.com/tutorials/install-ubuntu-desktop#1-overvi ew)或者其他⽹络资料安装。
⽅式2:在计算机上安装虚拟机软件,⽐如 VMware 、VirtualBox ,然后在虚拟机上 安装 Ubuntu系统。
⽅式3:由于 Linux 系统对开发者的友好性,Windows 10 操作系统已经⽀持内置的 Linux ⼦系统,可以参阅相关资料,开启并使⽤⼦系统。 读者若有计划在软件开发这个⽅向上有所深⼊,就不得不摆脱貌似简单实则低效的 ⽤⿏标“点来点去”的操作习惯,改为貌似复杂实则便捷⾼效的“命令⾏”。不论是 1.5.1节的 DOS 命令,还是此处介绍的 Linux 命令,⾄少要熟悉⼀种。
1.2.3 mac os系统
macOS 是美国苹果公司推出的操作系统(注意,历史上这个操作系统的名称有所变更, 2011年及之前称为 Mac OS X ,2012年⾄2015年称 OS X ),主要⽤于其 Macintosh(简称 Mac)系列的个⼈计算机上。 macOS 具有⾮常友好的视窗操作界⾯,并且与硬件配合堪称天⾐⽆缝(毕竟是同⼀家⽣产 的),这赢得了⼤众的欢迎(只是价格不怎么亲民)。对于开发者⽽⾔,图形化操作当然是 必须的。除此之外,前述的“⼿指不离开键盘”完成各种操作,在 macOS 中也能轻松实现, 因为 macOS 是基于 Uninx 的,它与 Linux 同宗同源,所以常⽤的 Linux 命令可以⽤在 macOS 上
1.2.4 IDE
什么是IDE
就是一个集成开发环境
IDE(Integrated Development Environment),全称是集成开发环境 ,是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。所有具备这一特性的软件或者软件套(组)都可以叫集成开发环境。
如:pycharm,viscode,
1.3 变量
如下:
x = 3
a = x + 1
print(a)
3
变量名称不以数字开头; 变量名称中可以包含英⽂字母(⼤写和⼩写)、数字以及下划线 _ 。不允许有其 他英⽂状态下的字符,如“+、-、#、!、@”等,也不能有空格。 ⼀般不使⽤单个的l(字母 L 的⼩写)、O(字母 o 的⼤写)、I(字母 i 的⼤ 写)作为变量名称,这也是为了提⾼可读性,避免误解。 ⼀般不⽤内置的 Python 函数来命名,这样会导致以后调⽤该函数的时候⽆法使⽤ 。 变量名称的长度可以任意,但不宜太长.
1.4 查询python内置关键字(保留字)keyword模块
import keyword
print(keyword.kwlist)
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', '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']
1.5算数运算符
运算符 描述 ⽰例 + 两个对象相加 1+2=3
- 得到负数或是⼀个数减去另⼀个数 2-3=-1
* 两个数相乘或是返回⼀个被重复若⼲次的字符串 2*3=6
/ 两个数相除 5/2=2.5
% 两个数相除后所得的余数 5%2=1
// 向下取整,返回两个数相除的整数 5//2=2
** 计算⼀个数的幂运算 5**2=25
1.5.1 加法(+)
2 + 3
5
2.3 + 3.1
5.4
a = 4
b = 6.2
a + b
10.2
1.5.2 减法(-)
如果没有特别定义,运算符 - 实现的两个数字相减——这⾥所说的数字,⽬前暂且是浮点 数、整数,如下操作:
a=4 b=9.9 print(a-b) -5.9
1.5.3 取相反数
运算符 - 的另外⼀个作⽤就是对某个数字取相反数:
a=-4
print(-(a))
4
1.5.4 乘法(*)
数学中,实现乘法的运算符是 ,但在编程语⾔中,使⽤的是键盘上的 * 。如果相乘的 是两个数字——⽬前讨论的是浮点数、整数,那么与数学中的运算结果⼀致。
a = 4 * 4
print(a)
16
对运算符 * 的描述中还有“返回⼀个被重复若⼲次的字符串”
1.5.5 除法(/ % //)
学中表⽰两个数相除,有多种形式,⽐如 。在 Python 语⾔中只能选⽤⼀ 种符号,对于 Python 3.x ,使⽤ / 符号作为除法运算符,计算结果与数学中的除法运算符 ÷ 计算结果相同。
>> 5 / 2
2.5
>>> 4.2 / 2
2.1
与除法有关的符号除了 / 之外,还有 % 和 //
1.5.6 //向下取整
运算符 // 的含义是“向下取整”
>> 5 / 2
2.5
>>> 5 // 2
2
5 / 2 的值是 2.5 ,结合图3-2-1所⽰的“向下取整”含义, “下边”的整数是 ,故 5 // 2 的结果是 2。 再来看负数情况:
>> -5 / 2
-2.5
>>> -5 // 2
-3
显然 “下边”的整数是 ,所以 -5 // 2 的结果为 -3 。 ⽤ // 按照“向下取整”原则得到的结果,也就是两个数字相除所得的商
1.5.7% 两个数相除后的余数
a = 5 % 2
print(a)
1
>> 7 // -9
-1
>>> 7 % -9
-2
1.5.8 幂** 2的3次方
在数学中,若⼲个数相乘可以写成该数字的⼏次幂,如 即为 。在 Python 中 ⽤ ** 运算符——两个乘法运算符,中间不能有空格——表⽰幂运算
>> 2 ** 3
8
>>> 2 ** -3
0.125
1.5.9 科学计数法( a X 10n)(1e10)
然表3-2-1中没有列出科学计数法的符号——其实它不是⼀个运算符,但由于在科学计算 中会经常⽤到,所以此处单独作为⼀项。在数学上,⼀个实数可以写成实数 与 的 积:a X 10n 其中:
n必须是整数;
a是实数,通常 1<= a <=,有时a 也会不在此范围,届时要调整n的⼤⼩。
这种表⽰数字的⽅法称为科学计数法(Scientific Notation),由阿基⽶德提出。 在 Python 中,为科学计数法设计了专有表⽰⽅式:
>> 1e10
10000000000.0
>>> 1E10
10000000000.0
⾯两种表⽰⽅法,均为 ——其中符号 e 不区分⼤⼩写。特别要注意,这是 Python 中⽐较特殊的现象,在其他⽅⾯通常要求区分⼤⼩写。
e后⾯如果是负整数,例如:
a = 2.3e-4
print(a)
0.00023
2.3e-4即表示2.3 X 10-4
任何⽤科学记数法表⽰的数,都是浮点数类型
>>> a = 2.3E-4
>>> type(a)
<class 'float'>
>>> b = 1E1
>>> b
10.0
>>> type(b)
<class 'float'>
如果表⽰ ,符号E前⾯是不是也可以省略数字 呢?
>> E8
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'E8' is not defined
在⼀个数学算式中,如果有多个表3-2-1中的运算符,在数学称为“混合运算”。⽤ Python 能实现混合运算,且运算优先级与数学上的规定保持⼀致。
>>> 3 ** 2 + 4 / 2 - 3 + 2
10.0
数学运算中,会⽤圆括号 明确优先运算的部分,它也被引⼊到了 Python 语⾔中,⽽ 且在 Python 中还特别提倡使⽤圆括号,这样能提⾼表达式的可读性——代码的可读性强, 是编程的第⼀原则。
>> 3 ** 2 + 4 / 2 - (3 + 2)
#3**2=9 + 2-5
6.0
Python 中的“⼤整数”不溢出现象,但是对 于浮点数运算⽽⾔,若超出了中央处理器所能允许浮点数范围,会出现算术溢出。
a = 1.9 ** 10000
print(a)
Traceback (most recent call last):
File "D:\pythonProject\student\基础·.py", line 1, in <module>
a = 1.9**10000
OverflowError: (34, 'Result too large')
所以,在进⾏浮点数运算的时候要注意了。 但是,如果是⼀个⽤科学计数法表⽰的浮点数超出了系统的浮点数范围,Python 会给出另 外⼀种处理,例如:
>>> n = 2E400
>>> n
inf
>>> type(n)
<class 'float'>
>>> 10 ** 400
100000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000
00000
>>> 10.0 ** 400
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')#溢出错误:(34,“结果太大”)
此处的 2E400 即 ,这个数字已经⼤于了宇宙中原⼦的总数(按照⽬前理论估 算,在可观测宇宙中的原⼦总数⼤约是 ),但是 Python 没有针对 2E400 出现算术溢 出,⽽是令其值为 inf,它表⽰“⽆穷⼤”,并且是⼀个浮点数——这是 Python 的规定,请 勿⽤数学上的规定来评判。 顺便⽐较 10 ** 400 与 10.0 ** 400的区别:前者返回的是整数——不会溢出,后者返回 结果应该是浮点数,溢出了。
1.6 用函数计算match库
术运算符能完成的是基本运算,为了便于计算,数学上还定义了其他⼀些常见函数,⽐如 三⾓函数、对数函数等。Python 语⾔中,有多种⽅式能够实现对常见函数计算,本节仅以 内置函数和标准库中的 math 模块为例给予这⽅⾯的简要介绍,更多有关数学计算问题,请 参阅《机器学习数学基础》
1.7 内置函数
Python 内置函数(Built-in Functions)是在本地计 算机中配置好 Python 开发环境之后就已经可以使⽤的函数,不需要单独定义。在第7章会 学习定义函数的⽅法,⽽内置函数是已经定义好了的,拿过来就可使⽤,正所谓“开箱即 ⽤”,但数量有限,
1.7.1 int() 和 float()类型转换
int() 和 float() 两个内置函数与3.1节所学习过的两个内置对象类型同名,⽤它们能够创 建相应对象或实现对象类型转化——“创建”的⽅法,此处仅讨论“类型转化”。
>>> int(3.14)
3
>>> int(-3.14)
-3
>>> int(3.56)
3
>>> int(-3.56)
-3
从上述操作结果不难总结出如下结论: int() 可以将浮点数转化为整数; int() 只是截取整数部分,不是“向下取整”,也不是“四舍五⼊”
看来这个函数不复杂,但“⿇雀虽⼩五脏俱全”,解剖它就能够对所有内置函数有基本了解。 请继续按照下述⽅式输⼊代码
help(int)
这⾥所⽤的 help() 也是⼀个内置函数,可以在表3-3-1中找到。其参数是 int 。注 意,int 后⾯没有 () ,此时表⽰的是函数 int() 对象。 然后敲回车键,会呈现如图3所⽰的内容(图中是部分内容截取),按向下键或滚动⿏ 标,可以查看没有显⽰的部分。
与查看 int() 函数的帮助⽂档的操作⼀样,在交互模式中输⼊ help(float) 即可查看 float() 函数的帮助⽂档,亦或在 Python 官⽅⽂档中查看该内容。建议读者认真阅读该⽂ 档,并对照如下操作理解其含义
>>> float(3)
3.0
1.7.2 divmod()同时返回两个数相除所得的商和余数
函数 divmod() 会同时返回两个数相除所得的商和余数。在交互模式中查看其帮助⽂档(输 ⼊ help(divmod) ),会看到如下所⽰的简洁描述:
divmod(x, y, /)
Return the tuple (x//y, x%y). Invariant: div*y + mod == x.
divmod() 的参数是两个实数 x 和 y ,返回的是 tuple类型对象(关于 tuple 请参阅第4 章4.4节),其中包括两部分,第⼀部分是 x//y ——表⽰商,第⼆部分是 x%y ——表⽰余 数。在⽂档中的式⼦: div*y + mod == x ,其中 div 是商,mod 是余数,这与说明 // 和 % 运算符是完全⼀致,请对照阅读。⽤以下操作熟悉这个函数的调⽤⽅法
>>> divmod(5, 2)
(2, 1)
>>> divmod(-5, 2)
(-3, 1)
>>> divmod(7, -9)
(-1, -2)
1.7.3 pow()函数作⽤与运算符 ** 相同求幂
⼀般情况下,函数 pow() 的作⽤与运算符 ** 相同,即计算某个数的幂,例如:
>>> 2 ** 3
8
a = pow(3,2)
print(a)
9
其中 pow() 的第⼀个参数 2 是底数,第⼆个参数 3 是指数。
an:其中 a叫做底数, n叫做指数,an 的结果叫做幂。
如果读者查看其⽂档,会发现对 pow()参数的描述⽅式有如下两种:
帮助⽂档中:pow(base, exp, mod=None) ;
官⽅⽂档中:pow(base, exp[, mod]) 。
其中的 base 和 exp 没有什么异议,重点看第三个参数: mod=None 表⽰此参数默认值是 None ,( None 是⼀个 Python 对象,表⽰没有定义或者没有值);[, mod] 表⽰此参数 可以省略,当省略的时候与 mod=None 等效.
如果对参数 mod 赋值, 函数 pow() 与 ** 运算符就有差别了。当 mod 不为 None 时,则计 算 base ** exp % mod ,并返回表达式的值(mod 为⾮零整数,exp⼤于零。建议读者通 过⽂档理解 exp⼩于零时的计算过程)
>>> 2 ** 3 % 5
3
>>> pow(2, 3, 5)
3
以上得到了2的3次方=8,再除以 5所得的余数5.
与运算符 *** 相⽐,通常 pow() 函数计算性能更好。
1.7.4 round()实现对⼀个实数的四舍五⼊
使⽤ round() 函数能够实现对⼀个实数的四舍五⼊——针对⼗进制数字⽽⾔。在交互模式 中完成如下操作,并结合数学中的“四舍五⼊”含义理解操作结果
>> round(3.14, 1)
3.1
>>> round(3.56)
4
>>> round(3.56, 0)
4.0
>>> round(356, -2)
400
>>> round(356, -1)
360
>>> round(-3.56, 1)
-3.6
>>> round(-356, -1)
-360
读者阅读官⽅⽂档(https://docs.python.org/3/library/functions.html#round),会看 到如下⽰例:
>>> round(2.675, 2)
2.67
根据数学知识, 按照四舍五⼊原则保留两位⼩数,结果应为 ,然⽽此处返回值 是 2.67 。在官⽅⽂档中明确说明:“This is not a bug”,并且给出了解释
1.7.5 max() 选出若⼲个数中的最⼤值
内置函数 max() 能够选出若⼲个数中的最⼤值,例如:
a = max(3, 3.14, 7, 28)
print(a)
28
1.7.5 min()返回数字中的最小值
manx() 的参数,每个数字之间⽤英⽂的逗号 , 隔开。同理,min() 函数则返回⼀系 列数字中的最⼩值。
a = min(3, 3.14, 7, 28)
print(a)
3
两个函数,除了可以如同以上那样使⽤,其参数还可以是“可迭代对象”(iterable)
1.7.6 dir()能够返回参数对象的属性和⽅法
如:
import math
print(dir(math))
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
1.8标准库math模块
准库中的 math 模块主要提供初等数学中常⽤函数,官⽅⽂档地址是 https://docs.python .org/3/library/math.html。请在本地交互模式中,输⼊ import math ,然后敲回车键,如 下所⽰:
import math
print(dir(math))
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
这⾥使⽤了内置函数 dir() ,它能够返回参数对象的属性和⽅法——在第2章2.4节初步接 触了对象的“属性”和“⽅法”
对于 dir(math) 的返回结果,也 可以理解为模块 math ⾥⾯提供的函数。不妨浏览⼀番这些函数名称,并与记忆中的初等数 学常⽤函数对⽐
这些函数怎么⽤?以余弦函数 cos 为例,根据⾃学经验,应该先看⼀看这个函数的⽂档:
help(match.cos)
上述写法,不能直接写 help(cos) ,因为函数 cos 是模块 math 的⼀员,注释(1) 引⼊的是这个模块,当调⽤其中的函数时,必须借助模块的名称 。
执⾏上述语句,可以看到 math.cos 的帮助⽂档
cos(x, /)
Return the cosine of x (measured in radians)
1.8.1math.cos()是以弧度(rad )为单位,并返回该值的余 弦
此可知,math.cos() 函数的中的参数 x 是以弧度(rad )为单位,并返回该值的余 弦。
下⾯以计算 为例演⽰ math.cos() 的使⽤⽅法:
>> alpha = 60 / 180 * math.pi # (2)
>>> math.cos(alpha) # (3)
0.5000000000000001
注释(2)将以⾓度为单位60°的 转化为以弧度为单位的 3分之1乘以π,但此处⽤浮点数表⽰。其中 还使⽤了 math.pi ,其值即为
>> math.pi
3.141592653589793
注释(3)即为调⽤余弦函数,并得到了返回值——有点奇怪,暂不⽤管太多。
>>> round(math.cos(math.pi/4) + math.log10(5) * math.exp(2), 2)
5.87
1.9. fractions 模块
根据之前所学,如果在 Python 中表⽰三分之一 ,只能⽤ 1/3 实现,即以浮点数近似地表⽰。
>>> 1/3
0.3333333333333333
有没有实现精确表⽰的⽅法呢?必须得有!这就是标准库中的 fractions 模块所要解决的 问题。
>> import fractions # (4)
>>> a = fractions.Fraction(60, 180) # (5)
>>> a
Fraction(1, 3)
>> 1 / 3 + 1 / 2
0.8333333333333333
import fractions
a = fractions.Fraction(1,3)
b = fractions.Fraction(1,2)
s = a + b
print(s)
5/6
此就实现了分数的精确计算。
输出(print函数)
用print()
在括号中加上字符串,就可以向屏幕上输出指定的文字。比如输出'hello, world'
,用代码实现如下:
print('hello world')
hello world
print()
函数也可以接受多个字符串,用逗号“,”隔开,就可以连成一串输出:
print('The quick brown fox', 'jumps over', 'the lazy dog')
The quick brown fox jumps over the lazy dog
print()
会依次打印每个字符串,遇到逗号“,”会输出一个空格.
print()
也可以打印整数,或者计算结果:
print(300)
300
print(100 + 200)
300
因此,我们可以把计算100 + 200
的结果打印得更漂亮一点:
print('100 + 200',100+200)
100 + 200= 300
注意,对于100 + 200
,Python解释器自动计算出结果300
,但是,'100 + 200 ='
是字符串而非数学公式,Python把它视为字符串。
输入(input)
现在,你已经可以用print()
输出你想要的结果了。但是,如果要让用户从电脑输入一些字符怎么办?Python提供了一个input()
,可以让用户输入字符串,并存放到一个变量里。比如输入用户的名字:
name = input()
当你输入name = input()
并按下回车后,Python交互式命令行就在等待你的输入了。这时,你可以输入任意字符,然后按回车后完成输入。
输入完成后,不会有任何提示,Python交互式命令行又回到>>>
状态了。那我们刚才输入的内容到哪去了?答案是存放到name
变量里了。可以直接输入name
查看变量内容:
name = input()
print(name)
数据类型
计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值。但是,计算机能处理的远不止数值,还可以处理文本、图形、音频、视频、网页等各种各样的数据,不同的数据,需要定义不同的数据类型。在Python中,能够直接处理的数据类型有以下几种:
整数(int)
Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1
,100
,-8080
,0
,等等。
计算机由于使用二进制,所以,有时候用十六进制表示整数比较方便,十六进制用0x
前缀和0-9,a-f表示,例如:0xff00
,0xa5b4c3d2
,等等。
对于很大的数,例如10000000000
,很难数清楚0的个数。Python允许在数字中间以_
分隔,因此,写成10_000_000_000
和10000000000
是完全一样的。十六进制数也可以写成0xa1b2_c3d4
。
浮点数(float)
浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,比如,1.23x109和12.3x108是完全相等的。浮点数可以用数学写法,如1.23
,3.14
,-9.01
,等等。但是对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,1.23x109就是1.23e9
,或者12.3e8
,0.000012可以写成1.2e-5
,等等。
整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的(除法难道也是精确的?是的!),而浮点数运算则可能会有四舍五入的误差。
字符串(str)
字符串是以单引号'
或双引号"
括起来的任意文本,比如'abc'
,"xyz"
等等。请注意,''
或""
本身只是一种表示方式,不是字符串的一部分,因此,字符串'abc'
只有a
,b
,c
这3个字符。如果'
本身也是一个字符,那就可以用""
括起来,比如"I'm OK"
包含的字符是I
,'
,m
,空格,O
,K
这6个字符。
如果字符串内部既包含'
又包含"
怎么办?可以用转义字符\
来标识,比如:
'I\'m \"OK\"!'
表示的字符串内容是:
I'm "OK"!
转义字符(\n
表示换行,\t
表示制表符,字符\
本身也要转义,)
转义字符\
可以转义很多字符,比如\n
表示换行,\t
表示制表符,字符\
本身也要转义,所以\\
表示的字符就是\
,可以在Python的交互式命令行用print()
打印字符串看看:
print('I\'m ok.')
print('I\'m learning\nPython.')
print('\\\n\\')
I'm ok.
I'm learning
Python.
\
\
如果字符串里面有很多字符都需要转义,r''
表示''
内部的字符串默认不转义
如果字符串里面有很多字符都需要转义,就需要加很多\
,为了简化,Python还允许用r''
表示''
内部的字符串默认不转义,可以自己试试:
>>> print('\\\t\\')
\ \
>>> print(r'\\\t\\')
\\\t\\
如果字符串内部有很多换行,用\n
写在一行里不好阅读,为了简化,Python允许用'''...'''
的格式表示多行内容,可以自己试试:
>>> print('''line1
... line2
... line3''')
line1
line2
line3
上面是在交互式命令行内输入,注意在输入多行内容时,提示符由>>>
变为...
,提示你可以接着上一行输入,注意...
是提示符,不是代码的一部分:
┌────────────────────────────────────────────────────────┐
│Command Prompt - python _ □ x │
├────────────────────────────────────────────────────────┤
│>>> print('''line1 │
│... line2 │
│... line3''') │
│line1 │
│line2 │
│line3 │
│ │
│>>> _ │
│ │
│ │
│ │
└────────────────────────────────────────────────────────┘
当输入完结束符```
和括号)
后,执行该语句并打印结果。
当输入完结束符```
和括号)
后,执行该语句并打印结果。
如果写成程序并存为.py
文件,就是:
print('''line1
line2
line3''')
布尔值(True False)(and or not)
布尔值和布尔代数的表示完全一致,一个布尔值只有True
、False
两种值,要么是True
,要么是False
,在Python中,可以直接用True
、False
表示布尔值(请注意大小写),也可以通过布尔运算计算出来:
>>> True
True
>>> False
False
>>> 3 > 2
True
>>> 3 > 5
False
布尔值可以用and
、or
和not
运算。
and
运算是与运算,只有所有都为True
,and
运算结果才是True
:
>>> True and True
True
>>> True and False
False
>>> False and False
False
>>> 5 > 3 and 3 > 1
True
or
运算是或运算,只要其中有一个为True
,or
运算结果就是True
:
>>> True or True
True
>>> True or False
True
>>> False or False
False
>>> 5 > 3 or 1 > 3
True
not
运算是非运算,它是一个单目运算符,把True
变成False
,False
变成True
:
>>> not True
False
>>> not False
True
>>> not 1 > 2
True
布尔值经常用在条件判断中,比如:
if age >= 18:
print('adult')
else:
print('teenager')
空值(None)
空值是Python里一个特殊的值,用None
表示。None
不能理解为0
,因为0
是有意义的,而None
是一个特殊的空值。
变量(等号=
是赋值语句)
变量的概念基本上和初中代数的方程变量是一致的,只是在计算机程序中,变量不仅可以是数字,还可以是任意数据类型。
变量在程序中就是用一个变量名表示了,变量名必须是大小写英文、数字和_
的组合,且不能用数字开头,比如:
a = 1
变量a
是一个整数。
t_007 = 'T007'
变量t_007
是一个字符串。
Answer = True
变量Answer
是一个布尔值True
。
在Python中,等号=
是赋值语句,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量,例如:
a = 123 # a是整数
print(a)
a = 'ABC' # a变为字符串
print(a)
123
ABC
这种变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错。例如Java是静态语言,赋值语句如下(// 表示注释):
int a = 123; // a是整数类型变量
a = "ABC"; // 错误:不能把字符串赋给整型变量
和静态语言相比,动态语言更灵活,就是这个原因。
请不要把赋值语句的等号等同于数学的等号。比如下面的代码:
x = 10
x = x + 2
如果从数学上理解x = x + 2
那无论如何是不成立的,在程序中,赋值语句先计算右侧的表达式x + 2
,得到结果12
,再赋给变量x
。由于x
之前的值是10
,重新赋值后,x
的值变成12
。
最后,理解变量在计算机内存中的表示也非常重要。当我们写:
a = 'ABC'
时,Python解释器干了两件事情:
-
在内存中创建了一个
'ABC'
的字符串; -
在内存中创建了一个名为
a
的变量,并把它指向'ABC'
。
也可以把一个变量a
赋值给另一个变量b
,这个操作实际上是把变量b
指向变量a
所指向的数据,例如下面的代码:
a = 'ABC'
b = a
a = 'XYZ'
print(b)
ABC
最后一行打印出变量b
的内容到底是'ABC'
呢还是'XYZ'
?如果从数学意义上理解,就会错误地得出b
和a
相同,也应该是'XYZ'
,但实际上b
的值是'ABC'
,让我们一行一行地执行代码,就可以看到到底发生了什么事:
执行a = 'ABC'
,解释器创建了字符串'ABC'
和变量a
,并把a
指向'ABC'
:
执行b = a
,解释器创建了变量b
,并把b
指向a
指向的字符串'ABC'
:
执行a = 'XYZ'
,解释器创建了字符串'XYZ',并把a
的指向改为'XYZ'
,但b
并没有更改:
所以,最后打印变量b
的结果自然是'ABC'
了。
常量(就是不能变的变量)(inf无穷大)
所谓常量就是不能变的变量,比如常用的数学常数π就是一个常量。在Python中,通常用全部大写的变量名表示常量:
PI = 3.14159265359
但事实上PI
仍然是一个变量,Python根本没有任何机制保证PI
不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法,如果你一定要改变变量PI
的值,也没人能拦住你。
最后解释一下整数的除法为什么也是精确的。在Python中,有两种除法,一种除法是/
:
>>> 10 / 3
3.3333333333333335
/
除法计算结果是浮点数,即使是两个整数恰好整除,结果也是浮点数:
>>> 9 / 3
3.0
还有一种除法是//
,称为地板除,两个整数的除法仍然是整数:
>>> 10 // 3
3
你没有看错,整数的地板除//
永远是整数,即使除不尽。要做精确的除法,使用/
就可以。
因为//
除法只取结果的整数部分,所以Python还提供一个余数运算,可以得到两个整数相除的余数:
>>> 10 % 3
1
无论整数做//
除法还是取余数,结果永远是整数,所以,整数运算结果永远是精确的。
Python支持多种数据类型,在计算机内部,可以把任何数据都看成一个“对象”,而变量就是在程序中用来指向这些数据对象的,对变量赋值就是把数据和变量给关联起来。
对变量赋值x = y
是把变量x
指向真正的对象,该对象是变量y
所指向的。随后对变量y
的赋值不影响变量x
的指向。
注意:Python的整数没有大小限制,而某些语言的整数根据其存储长度是有大小限制的,例如Java对32位整数的范围限制在-2147483648
-2147483647
。
Python的浮点数也没有大小限制,但是超出一定范围就直接表示为inf
(无限大)。
字符编码
我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题。
因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果要表示更大的整数,就必须用更多的字节。比如两个字节可以表示的最大整数是65535
,4个字节可以表示的最大整数是4294967295
。
由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII
编码,比如大写字母A
的编码是65
,小写字母z
的编码是122
。
但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312
编码,用来把中文编进去。
你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS
里,韩国把韩文编到Euc-kr
里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。
因此,Unicode字符集应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode标准也在不断发展,但最常用的是UCS-16编码,用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
现在,捋一捋ASCII编码和Unicode编码的区别:ASCII编码是1个字节,而Unicode编码通常是2个字节。
字母A
用ASCII编码是十进制的65
,二进制的01000001
;
字符0
用ASCII编码是十进制的48
,二进制的00110000
,注意字符'0'
和整数0
是不同的;
汉字中
已经超出了ASCII编码的范围,用Unicode编码是十进制的20013
,二进制的01001110 00101101
。
你可以猜测,如果把ASCII编码的A
用Unicode编码,只需要在前面补0就可以,因此,A
的Unicode编码是00000000 01000001
。
新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。
所以,本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8
编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:
字符 | ASCII | Unicode | UTF-8 |
---|---|---|---|
A | 01000001 | 00000000 01000001 | 01000001 |
中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
从上面的表格还可以发现,UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。
搞清楚了ASCII、Unicode和UTF-8的关系,我们就可以总结一下现在计算机系统通用的字符编码工作方式:
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:
所以你看到很多网页的源码上会有类似<meta charset="UTF-8" />
的信息,表示该网页正是用的UTF-8编码。
Python的字符串
搞清楚了令人头疼的字符编码问题后,我们再来研究Python的字符串。
在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,Python的字符串支持多语言,例如:
>>> print('包含中文的str')
包含中文的str
ord()函数 (获取字符的整数表示)
chr()
函数把编码转换为对应的字符
对于单个字符的编码,Python提供了ord()
函数获取字符的整数表示,chr()
函数把编码转换为对应的字符:
print(ord('A'))
print(ord('中'))
print(chr(66))
print(chr(25991))
65
20013
B
文
如果知道字符的整数编码,还可以用十六进制这么写str
:
>>> '\u4e2d\u6587'
'中文'
两种写法完全是等价的。
由于Python的字符串类型是str
,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str
变为以字节为单位的bytes
。
Python对bytes
类型的数据用带b
前缀的单引号或双引号表示:
x = b'ABC'
要注意区分'ABC'
和b'ABC'
,前者是str
,后者虽然内容显示得和前者一样,但bytes
的每个字符都只占用一个字节。
encode()
方法可以编码为指定的bytes(字节)
b
以Unicode表示的str
通过encode()
方法可以编码为指定的bytes
,例如:
print('ABC'.encode('ascii'))
print('中文'.encode('utf-8'))
print('中文'.encode('ascii'))
b'ABC'
b'\xe4\xb8\xad\xe6\x96\x87'
Traceback (most recent call last):
File "D:\pythonProject\student\基础·.py", line 5, in <module>
print('中文'.encode('ascii'))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
Process finished with exit code 1
纯英文的str
可以用ASCII
编码为bytes
,内容是一样的,含有中文的str
可以用UTF-8
编码为bytes
。含有中文的str
无法用ASCII
编码,因为中文编码的范围超过了ASCII
编码的范围,Python会报错。
在bytes
中,无法显示为ASCII字符的字节,用\x##
显示。
decode()
方法要把bytes
变为str
反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes
。要把bytes
变为str
,就需要用decode()
方法:
>>> b'ABC'.decode('ascii')
'ABC'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'
如果bytes
中包含无法解码的字节,decode()
方法会报错:
>>> b'\xe4\xb8\xad\xff'.decode('utf-8')
Traceback (most recent call last):
...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
errors='ignore'
忽略错误的字节
如果bytes
中只有一小部分无效的字节,可以传入errors='ignore'
忽略错误的字节:
>>> b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
'中'
len()
函数计算包含多少个字符
要计算str
包含多少个字符,可以用len()
函数:
>>> len('ABC')
3
>>> len('中文')
2
len()
函数计算的是str
的字符数,如果换成bytes
,len()
函数就计算字节数:
>>> len(b'ABC')
3
>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
6
>>> len('中文'.encode('utf-8'))
6
可见,1个中文字符经过UTF-8编码后通常会占用3个字节,而1个英文字符只占用1个字节。
在操作字符串时,我们经常遇到str
和bytes
的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str
和bytes
进行转换。
由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;
第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
格式化
最后一个常见的问题是如何输出格式化的字符串。我们经常会输出类似'亲爱的xxx你好!你xx月的话费是xx,余额是xx'
之类的字符串,而xxx的内容都是根据变量变化的,所以,需要一种简便的格式化字符串的方式。
在Python中,采用的格式化方式和C语言是一致的,用%
实现,举例如下:
print( 'Hello, %s' % 'world')
'Hello, world'
print('Hi, %s, you have $%d.' % ('Michael', 1000000))
'Hi, Michael, you have $1000000.'
你可能猜到了,%
运算符就是用来格式化字符串的。在字符串内部,%s
表示用字符串替换,%d
表示用整数替换,有几个%?
占位符,后面就跟几个变量或者值,顺序要对应好。如果只有一个%?
,括号可以省略。
占位符
常见的占位符有:
占位符 | 替换内容 |
---|---|
%d | 整数 |
%f | 浮点数 |
%s | 字符串 |
%x | 十六进制整数 |
其中,格式化整数和浮点数还可以指定是否补0和整数与小数的位数:
print('%2d-%02d' % (3, 1))
print('%.2f' % 3.1415926)
3-01
3.14
如果你不太确定应该用什么,%s
永远起作用,它会把任何数据类型转换为字符串:
>>> 'Age: %s. Gender: %s' % (25, True)
'Age: 25. Gender: True'
有些时候,字符串里面的%
是一个普通字符怎么办?这个时候就需要转义,用%%
来表示一个%
:
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'
format()格式化字符串的方法是
另一种格式化字符串的方法是使用字符串的format()
方法,它会用传入的参数依次替换字符串内的占位符{0}
、{1}
……,不过这种方式写起来比%要麻烦得多:
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成绩提升了 17.1%'
f-string 格式化字符串的方法是
f
最后一种格式化字符串的方法是使用以f
开头的字符串,称之为f-string
,它和普通字符串不同之处在于,字符串如果包含{xxx}
,就会以对应的变量替换:
>>> r = 2.5
>>> s = 3.14 * r ** 2
>>> print(f'The area of a circle with radius {r} is {s:.2f}')
The area of a circle with radius 2.5 is 19.62
上述代码中,{r}
被变量r
的值替换,{s:.2f}
被变量s
的值替换,并且:
后面的.2f
指定了格式化参数(即保留两位小数),因此,{s:.2f}
的替换结果是19.62
。
小明的成绩从去年的72分提升到了今年的85分,请计算小明成绩提升的百分点,并用字符串格式化显示出'xx.x%'
,只保留小数点后1位:、
s1=int(input('请输入去年的成绩'))
s2=int(input('请输入今年的成绩'))
r=(s2-s1)/s1*100
print('小明的成绩提升了%2.1f%%'%r)
print(f'小明的成绩提升了{r:.1f}%')
list(集合)
Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。
比如,列出班里所有同学的名字,就可以用一个list表示:
>>> classmates = ['Michael', 'Bob', 'Tracy']
>>> classmates
['Michael', 'Bob', 'Tracy']
变量classmates
就是一个list。用len()
函数可以获得list元素的个数:
>>> len(classmates)
3
用索引来访问list中每一个位置的元素,记得索引是从0
开始的:
>>> classmates[0]
'Michael'
>>> classmates[1]
'Bob'
>>> classmates[2]
'Tracy'
>>> classmates[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range#索引错误:列表索引超出范围
当索引超出了范围时,Python会报一个IndexError
错误,所以,要确保索引不要越界,记得最后一个元素的索引是len(classmates) - 1
。
如果要取最后一个元素,除了计算索引位置外,还可以用-1
做索引,直接获取最后一个元素:
>>> classmates[-1]
'Tracy'
以此类推,可以获取倒数第2个、倒数第3个:
>>> classmates[-2]
'Bob'
>>> classmates[-3]
'Michael'
>>> classmates[-4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
当然,倒数第4个就越界了。
append()方法可以往list中追加元素到末尾
list是一个可变的有序表,所以,可以往list中追加元素到末尾:
classmates = ['Michael', 'Bob', 'Tracy']
classmates.append('Adam')
print(classmates)
['Michael', 'Bob', 'Tracy', 'Adam']
insert()可以把元素插入到指定的位置,索引添加指定位置
也可以把元素插入到指定的位置,比如索引号为1
的位置:
classmates = ['Michael', 'Bob', 'Tracy']
classmates.append('Adam')
print(classmates)
classmates.insert(1, 'Jack')
print(classmates)
['Michael', 'Bob', 'Tracy', 'Adam']
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
pop()删除list末尾的元素
要删除list末尾的元素,用pop()
方法:
classmates = ['Michael', 'Bob', 'Tracy']
classmates.append('Adam')
print(classmates)
classmates.insert(1, 'Jack')
print(classmates)
classmates.pop()
print(classmates)
classmates.pop()
print(classmates)
['Michael', 'Bob', 'Tracy', 'Adam']
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
['Michael', 'Jack', 'Bob', 'Tracy']
['Michael', 'Jack', 'Bob']
pop(i)删除指定位置的元素,其中i
是索引位置
要删除指定位置的元素,用pop(i)
方法,其中i
是索引位置:
classmates = ['Michael', 'Bob', 'Tracy']
classmates.append('Adam')
print(classmates)
classmates.pop(1)
print( classmates)
['Michael', 'Bob', 'Tracy', 'Adam']
['Michael', 'Tracy', 'Adam']
某个元素替换成别的元素
要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:
classmates = ['Michael', 'Bob', 'Tracy']
classmates.append('Adam')
print(classmates)
classmates[1] = 'Sarah'
print( classmates)
['Michael', 'Bob', 'Tracy', 'Adam']
['Michael', 'Sarah', 'Tracy', 'Adam']