Python基础手册P2 基本数据类型基本类型
Python 基本数据类型
。。。
今天没有想要写在开头的废话,,,好烦,要不破例直接开始吧。
变量与常量
变量
Python 是一门动态语言,这意味着 Python 变量本身的类型是不固定的。
在 Python 中使用变量前不用声明(不用写类似 int a;
的语句),在首次使用前为其赋初始值就行(直接用 a = 0
)。
常量
实际上,在 Python 语法中并没有定义常量。
但是 PEP 8 定义了常量的命名规范为大写字母和下划线组成。在实际应用中,这种“常量”首次赋值后,无法阻止其他代码对其进行修改或删除。
要使用真正的常量,可以自己实现一个,例如:constants-in-python。
空值
Python 中使用 None
来代表空值。None
在交互式命令行中不会显示,但可以用 print()
打印出来:
1 | None |
布尔值
Python 中有布尔值 True
和 False
。
真值问题
代表 ‘假’ 的值有:False
,None
,0
,''
,[]
,{}
,…;
其余值为真。
布尔值的相关的运算
逻辑运算符 | 相当于C中的 |
---|---|
and |
&& |
or |
` |
not |
! |
⚠️【注意 and
的优先级高于 or
。
比较运算符 |
---|
< , > , == , != |
使用比较运算符得到的结果是布尔值(True
或 False
)。
使用逻辑运算符得到的结果未必是布尔值:
具体的运算情况可以参考下面这段程序生成的表:
1 | # **注意,是第一列的值 and|or 第一行的值!** |
从中可以看到,and
的规则是:
前后两者 皆为真 ,返回 后 者;
前后两者 有一假 ,返回 假 者;
前后两者 皆为假 ,返回 前 者;
or
的规则是:
前后两者 皆为真 ,返回 前 者;
前后两者 有一真 ,返回 真 者;
前后两者 皆为假 ,返回 后 者;
此外,not
的规则是:
若对象为 真 ,返回
False
若对象为 假 ,返回True
数字
int, float
数字 | 含义 | 表示范围 | 精度 |
---|---|---|---|
int | 整数 | 大小没有限制 | 始终是准确的 |
float | (基于二进制的)浮点数 | 有一定大小限制,超出后表示为inf | 和C一样,不准确 |
复数
Python 还内置了对 复数 的支持,使用后缀 j
或 J
表示虚数部分(例如,3+5j
)。
1 | 3 + 1j a = |
关于这部分详见官方文档。
其他数字类型
在标准库中,python 还有对 精确小数 Decimal(基于十进制的浮点数)和 分数 Fraction 等其他数字类型的支持。
Decimal (小数)
在 Python 的标准库中,decimal
库提供了 基于十进制的浮点数 Decimal 类型,这种数字类型修复了 float 的不准确问题,可以用 Decimal 实现更加精准的数学计算(但也不是绝对的准确,仍存在误差)。
1 | from decimal import * |
正如上例,要使用 Decimal
类型,
首先要
import decimal
;然后用
decimal.Decimal(Num)
来获取一个 Decimal 实例,这里的 Num 可以是如下几种:1
2
3
4
5
6
7
8
9
10'3.14') # 内容是 float 的字符串 Decimal(
Decimal('3.14')
0, (3, 1, 4), -2)) # tuple (sign, digit_tuple, exponent),得到的值是 (-1) * sign * digit_tuple 代表数字 * 10 ^ exponent Decimal((
Decimal('3.14')
314) # int,float 都可以 Decimal(
Decimal('314')
314)) # 另一个 decimal 实例 Decimal(Decimal(
Decimal('314')
' 3.14 \\n') # 前后可以有空白字符 Decimal(
Decimal('3.14')decimal.getcontext().prec 代表有效位数,
- 通过
print(decimal.getcontext().prec)
来查看当前值,默认是28位 - 通过
decimal.getcontext().prec = Places
来设置有效位数,这个精度的取值是[1, MAX_PREC]
,MAX_PREC取值在64位机器上是999999999999999999
,32位为425000000
(这是因为这个值要可以转化为C的整型,详见Python版的源码)!
- 通过
加减乘除运算入常
Fraction (分数)
在 fractions
库中,定义了 Fraction
类型,用以表达分数,加减乘除运算入常。
使用方法如下:
1 | from fractions import * |
字符串
字符串的表示
Python 中,字符串可以用单引号 ('...'
) 或双引号 ("..."
) 标识单行内的字符串,
还可以使用连续三个单/双引号('''...'''
或 """..."""
)表示与格式化的多行字符。
Python没有单独的字符类型;一个字符就是一个简单的长度为1的字符串。
1 | '1\ st = |
⚠️【注意】单引号可以包含双引号,'asd"123"fgh'
是允许的,同样 '''
中也可以包含 """
。
字符编码
首先,附上几种字符编码的比较:
| 编码 | 长度 | ‘A’ | ‘中’ |
| – | – | – | – |
| ASCII | 1 Byte | 01000001 | (无此字符) |
| Unicode | 通常是2 Byte | 00000000 01000001 (ASCII前补零) | 01001110 00101101 |
| UTF-8 | 可变(1~6 Byte)| 01000001 (UTF-8包含着ASCII)| 11100100 10111000 10101101 |
Python3.x 默认用 Unicode 编码字符串。
编码 <=> 字符 的函数:
ord()
:获取字符的整数表示;chr()
:把编码转换成对应的字符;
例如:
1 | ord('A') |
Python 的字符串类型是 str
。
str
在内存中以 Unicode 表示,一个字符对应若干字节。
在写入二级缓存(本地->硬盘 | 远程->网络)时,str
将变为bytes
。
bytes
以字节为单位。
Python 用带 b
前缀的单/双引号表示 bytes
。
str | bytes |
---|---|
'ABC' |
b'ABC' |
str <=> bytes:
- encode(): str –> bytes
1 | 'abc'.encode('ascii') |
- decode(): bytes –> str
1 | b'abc'.decode('ascii') |
⚠️【注意】为避免乱码问题,应始终使用 utf-8
编码对 str
和 bytes
进行转换。
转义字符
Python 字符串中可以使用转义字符,可以参考下表:
转义字符 | 描述 |
---|---|
\ (在行尾时) |
续行符 |
\\ |
反斜杠符号 |
\' |
单引号 |
\" |
双引号 |
\a |
响铃 |
\b |
退格(Backspace) |
\e |
转义 |
\000 |
空 |
\n |
换行 |
\v |
纵向制表符 |
\t |
横向制表符 |
\r |
回车 |
\f |
换页 |
\xxx |
八进制数,例如:'\100' 代表 '@' |
\oyy |
八进制数,yy代表的字符,例如:'\o12' 代表换行 |
\xyy |
十六进制数,yy代表的字符,例如:'\x0a' 代表换行 |
\uxxxx |
十六进制数,xxxx代表的字符,例如:'\u4e2d\u6587' 代表 '中文' |
\other |
其它的字符以普通格式输出,例如:'\sds' 代表 '\\sds' |
若要取消转义,可以给字符串 r
前缀:
1 | 'C:\some\name') # here \n means newline! print( |
基本字符串操作
获取字符串长度
Python 内置的 len()
函数可以获取多种类型的对象长度,包括字符串。
1 | len(word) |
字符串连接
- 相邻的两个字符串文本自动连接在一起。
1 | 'Py' 'thon' |
- 字符串的
+
与*
字符串可以由 + 操作符连接(粘到一起),可以由 * 表示重复。
1 | # 3 times 'un', followed by 'ium' |
字符串插值
字符串的插值主要有 4 种方式:
- 字符串连接
1 | 123 a = |
%
元组插值
1 | 123 a = |
- 字符串的
format
方法
1 | 'a = {arg_a}, b = {arg_b}, c = {arg_c}'.format(arg_a="东方", arg_b=123, arg_c=333.44+8j) |
或者也可以匿名:
1 | 'Another way: {0}, {2}, {1}, {3}'.format("zero", 2, 1.0, 3) |
f-string
Python 3.6 引入了 f-string
,让插值更加优雅:
1 | 123 a = |
更多关于 f-string
的说明,可以参考 realpython的这篇文章,或者查看 f-string
的来源:PEP 498 – Literal String Interpolation。
字符串切分
用字符串的 split 方法可以以指定字符串为分割切分字符串:
1 | 'a b c'.split(' ') |
字符串替换
用字符串的 replace 方法可以替换字符串的一部分:
1 | 'he-*-ll-*-o--'.replace('-*-', '...') |
字符串索引及切片
- 索引
字符 | P | y | t | h | o | n |
---|---|---|---|---|---|---|
正向索引 | 0(-0) | 1 | 2 | 3 | 4 | 5 |
反向索引 | -6 | -5 | -4 | -3 | -2 | -1 |
1 | 'Python' word = |
- 切片
索引用于获得单个字符,切片 让你获得一个子字符串。
切片的规则是:str[起始:末尾:间隔]
* 起始:开始的索引(取),缺省为0
* 末尾:结束的索引(不取),缺省时,取到字符串最后一个字符(取得到)
* 间隔:每取一个之后间隔几个(>0),缺省为1,为负值时倒着取
1 | 0:2] # characters from position 0 (included) to 2 (excluded) word[ |
⚠️【注意】切片包含起始的字符,不包含末尾的字符。s[:i] + s[i:] == s
⚠️【注意】字符串索引、切片都是只读的,不可以给字符串索引、切片赋值!
正则表达式
字符串的使用肯定绕不过正则表达式,python 内置了正则表达式模块—— re
。
我不在这里介绍正则表达式的写法,只是展示怎么用 Python 完成常见的正则表达式操作。正则本身有问题,请到 https://regexr.com。
匹配:
1 | import re |
提取:
1 | import re |
用 m.groups() 即可获取提取到的组:('123', '456')
。
切分:
1 | # 切分 |
集合类型
其实,在我心中,字符串也是种集合类型(你学过C语言就会有同感了,字符串不过是字符组成的 list 而已)。所以,刚才介绍字符串的很多操作,在接下来的 list 中也一样适用。
list
list:列表,写在 []
中。
1 | l0 = [] |
索引&切片:
- get:
lst[索引 || 切片]
- set:
lst[索引 || 切片] = 值
1 | >>> l[0] = 3.14 |
索引&切片 和字符串中介绍的相同,不了解可以这回去看。
我们来看 list 的基本操作:
尾部添加:lst.append(值)
, lst.extend(iterable)
1 | l = [] |
append 和 extend 一个是添加单个元素,一个是添加一系列元素。
利用切片,append 方法就等效于 lst[len(lst):] = [值]
, 而 extend 即 lst[len(lst):] = iterable
。
插入:lst.insert(索引, 值)
1 | l = [] |
删:lst.remove(值)
, lst.pop(索引)
, clear()
remove 是删除 list 中存在的一个值,若不存在,会报 ValueError。
pop 是删除 list 中给定索引处的值,若索引越界,会报 IndexError。
clear 就是清空(删除)所有元素;也可以用 del a[:]
完成类似的操作。
1 | l |
其他操作:
list.index(x[, start[, end]])
: 你给值,它返索引list.count(x)
: 你给值,它告诉你有几个list.sort(key=None, reverse=False)
: 一种比较快的原址排序list.reverse()
: 列表反转,调个个(这个词好怪a,我的问题嘛?)list.copy()
: 返一个自己的浅拷贝。
关于 list ,可以写的东西实在太多了,都可以单独再写一篇,专门研究了。。。(以后再说吧,可能我会写吧,用了复习数据结构课。)
tuple
tuple:元组,和 list 类似,只是常写在 ()
中。
tuple 可以 get,不能set。也就是说,不能 append、不能 pop、不能索引赋值。
1 | 1,2,3) t = ( |
注意,刚才我写了一句“tuple常写在()
中”,何来此“常”,tuple 不就是写在圆括号里的嘛?如果你有此疑问,一定是没有好好读过文档。
给你个改过自新的机会:https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences:
文档里写了:
A tuple consists of a number of values separated by commas.
意思是说:“元组(tuple)是一系列用逗号分开的值!”,可没提用圆括号扩起来的呀,再看看这个例子:
1 | 12345, 54321, 'hello!' t = |
可见,tuple 对 Python 中例如函数参数的一系列元素的打包传递相当有用!
set
set
是保证元素唯一的无序集合。
我们一般也就用它来消除重复,保证唯一。当然,你应该知道,set
就大概对应于数学里的「集合」,所以 set
可以算 病娇茶部 并、交、差、补(你可以想象,数学那种补是不能算的,但可以算「对称差」)。
创建一个 set 有两种写法:set()
函数和使用花括号 {ele1, ele2, ...}
。但如果你要建空 set,只能用 set()
,而不能用 {}
!因为你应该知道,{}
建的是空字典。
1 | s = {} |
1 | a |
dict
dict:字典,键值对,底层实现是哈希表。字面值写作 {key1: value1, key2: value2, ...}
。
既然 dict 都写成和 set 一样的 {}
了,那你看可以想象,dict 也可以保证唯一性 —— dict保证 key 的唯一。
key 可以是任何「不可变」的值,也就是说,数字、字符串、不包含可变元素的元组都可以作为 key。
1 | 1: 'abc', '2': 2.0001} d = { |
1 | 'jack': 4098, 'sape': 4139} tel = { |
用 dict()
函数可以有更多初始化字典的技巧,我随便从文档抄两个,你细品:
1 | dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) |
推导式
推导式(comprehensions)是用来创建集合类型实例的。
比如,你想建一个“1到10的平方组成的list”,你如何来写代码?
当然,数据量不大,我们肯定可以这样:
1 | a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] |
但如果是1~100,1~100000呢?你想用循环对吧:
1 | a = [] |
但这样不够简洁!
“1到10的平方组成的list”,说起来就一句话,代码也应该简简单单一行就完成!「推导式」就是干这个的:
1 | 2 for x in range(1, 11)] [x** |
推导式的一般形式是:
1 | [表达式 任意个for或if句] |
这个例子可以给你个比较好的印象:
1 | for x in [1,2,3] for y in [3,1,4] if x != y] [(x, y, x*y) |
其实准确的说,我们刚才写的这些都是「列表推导式」。我们还有「set推导式」甚至是「dict推导式」。
1 | for x in 'abracadabra' if x not in 'abc'} {x |
你可能还想写这个:
1 | 2 for x in range(1, 11)) (x** |
哈哈,有点不一样了,这次它给你返了个 generator——生成器,这就不是推导式了,这里不做介绍,后面我们再讨论这东西。
最后,再看两个很有意思的例子:
1 | for j in range(1, i+1)] for i in range(1, 10)] [[(j, i, j*i) |
乘法表,这两种写法效果是一样的。
1 | matrix = [ |
没错!矩阵转置,利用推导式中只用一行代码就可以实现。
未完待续…
(最近这两天都在补作业呀、补作业呀、补作业呀…不补作业的时候还要打游戏…忙得很。而且最近练习双拼,中文打字速度直线下降,所以这篇写了好久。现在作业大概补完了,双拼也已有了小成(大概?),以后应该会快一些了。)
Next: 【Python流程控制】