写在前面:本文基于Python 3.x
基础数据类型
数值类型
python中只有以下几种类型
1 | 类型 示例 |
注意:
- 整数无穷精度
- 浮点数精度和C语言中的双精度浮点数相同
- 数值类型为不可变对象,值改变之后会创建新内存
运算
支持最基本的数学运算符号:+ - * / % **
、取正负+x -x
,地板除法//
,除法和取模divmod(x, y)
:
1 | divmod(5, 2) |
- **:次方
- //:地板除法
math.ceil()
天花板运算- ‘+’和’*’也能处理字符串
除了上面的基础算术运算符,还支持很多数值类型的运算符,例如:取反(~)、位移(>>)、位与(&)、位异或(^)、逻辑与(and)、逻辑或(or)
。
还有一些内置数学函数:
1 | pow():求幂,如pow(2,3)=8 |
对于小数和分数有相应的模块:decimal、fraction
注意,不能用==和!=进行浮点数比较;逻辑and、or返回的是表达式的值而不是bool
布尔类型
- python中bool类型是int类型的一个子类
- python中的任何一个数据对象要么是True,要么是False
1 | True False |
None是一种特殊的数据对象,像数值1、字符串’a’一样,只不过内存中这个数据对象里面存储的数据是我们不得而知的,但它永远表示为False。
1 | 2 or 3,3 or 2 |
再次说明,and、or返回的不是True/False的布尔值,而是逻辑表达式的运算结果。
等值比较
在python中,只要两个对象的类型相同,且它们是内置类型(字典除外),那么这两个对象就能进行比较。== != < <= > >=
1 | bool([1,2,[3,3]] < [1,2,[3,4]]) |
字符串也可以进行比较
1 | "ac" > "ab" < "ad" |
None对象只能参与等值和不等值比较
1 | None == None |
python支持连续比较,连续比较时等价于使用and运算。
注意:is比较的是内存对象;而==比较的是值
字符串
字符串为不可改变对象
字符串常量
python中可以使用单引号、双引号、三引号包围字符串,并可以使用反斜线转义特殊字符:
- 单、双引号是完全一致的,不像其他语言一样有强、弱引用之分
- 三引号(
'''xxx'''
或"""xxx"""
)包围的字符完全是字面符号,包围什么就得到什么,包括换行,且不会进行任何转义、替换等- 使用这种块字符串的方式,在输入需要换行的字符串时非常方便
- 而且可以作为块注释符注释一段代码。这表示这段被包围的代码解释为字符串,但因为没有赋值给变量,所以直接丢弃了
- 反斜线
\
可以转义特殊字符,例如在字符串中保留单引号"a\'b"
但是python在输出字符串的时候,总是倾向于使用单引号,除非字符串中包含了单引号。对于那些非打印字符,将总是使用十六进制的方式输出。
1 | '''aaaa |
也可以使用r
来声明后面的字符串是raw字符串,这里面的所有字符都是字面意义的,不会进行任何转义。
注意,raw字符串不能以反斜线结尾,除非对其转义。例如
r'abc\ndef\'
是错误语法,但r'abc\ndef\\'
是正确的语法,它表示后面有两个反斜线字符。
切片索引
可以通过索引从字符串中取元素:
str[1]
索引位可以是负数,表示从尾部开始取元素
分片的方式是使用[i:j]
或[i:j:k]
的方式,表示从索引位i开始取到索引位j(不包含j),i或j都可以省略。如果指定了k,则表示每隔k个元素取一次,也就是取一次元素之后跳过(k-1)一个元素。i、j、k都可以使用负数。
格式化
使用%作占位符:
1 | "long" who1 = |
可以使用字典索引
1 | "%(name1)s with %(name2)s" % {"name1":"longshuai", "name2":"xiaofang"} |
也可以使用format()来格式化字符串时,使用在字符串中使用{}
作为占位符,占位符的内容将引用format()中的参数进行替换。可以是位置参数、命名参数或者兼而有之。
1 | # 位置参数 |
也有内置函数format()
1 | '{0:.2f}'.format(1.2345) |
字符串方法
列表
列表类型是一个容器,它里面可以存放任意数量、任意类型的数据。
1 | 1, 2, 3], "a", "b", [4, "c"]] L = [[ |
列表是可变对象
上面是L = ["a", "b", "c"]
列表的图示。变量名L存储了列表的内存地址,列表内部包含了类型声明、列表长度等元数据,还保存了属于列表的3个元素的内存地址。需要注意的是,列表元素不是直接存在列表范围内的,而是以地址的形式保存在列表中。
列表构造
有两种常用的构造列表方式:
- 使用中括号
[]
- 使用list()构造方法
使用(中)括号构建列表时,列表的元素可以跨行书写,这是python语法中各种括号类型的特性。
1 | # 空列表 [] |
列表支持+ * +=
符号操作和切片索引等序列操作
sort()是列表类型的方法,只适用于列表;sorted()是内置函数,支持各种容器类型。
迭代和解析
列表是一个序列,可以使用in测试,使用for迭代。
1 | "a","b","c","d"] L = [ |
列表解析,它指的是对序列中(如这里的列表)的每一项元素应用一个表达式,并将表达式计算后的结果作为新的序列元素(如这里的列表)。
1 | for i in "abcdef" ] [ i |
元组
元组和列表一样,都是容器型的数据结构,且都是序列,所以容器中的元素都是按照索引位置有序存放的。所以,可以进行索引取值、切片等序列通用操作。
不同的是,元组是不可变序列,无法原处修改,意味着修改元组必须创建新的元组对象。
构造
1 | 1,2,3,4) ( |
元组中可以嵌套任意类型的数据对象。
操作
元组支持+ *
符号操作、可以通过+=
的方式进行二元赋值
因为元组是不可变对象,所以可以使用hash()进行hash:
1 | hash(T) |
因为元组是不可变对象,所以没有直接方法修改元组,只能通过其它手段根据原始元组间接地构造新元组。切片返回的元组也是一种修改方式。
字典
dict是一个hashtable数据结构,除了数据类型的声明头部分,还主要存储了3部分数据:一个hash值,两个指针。
这个hash值是根据key运用内置函数hash()来计算的,占用8字节(64位机器)。除了hash值,后面两个是指针,这两个指针分别是指向key、指向value的指针,每个指针占用一个机器字长,也即是说对于64位机器各占用8字节,所以一个dict的元素,除了实际的数据占用的内存空间,还额外占用24字节的空间。
对比列表
python中list是元素有序存储的序列代表,dict是元素无序存储的代表。它们都可变,是python中最灵活的两种数据类型。
但是:
dict的元素检索、增删改速度快,不会随着元素增多、减少而改变。但缺点是内存占用大
list的元素检索、增删改速度随着元素增多会越来越慢(当然实际影响并没有多大),但是内存占用小
换句话说,dict是空间换时间,list是时间换空间。
构造
有几种构造字典的方式:
- 使用大括号包围
- 使用dict()构造方法,dict()构造有3种方式:
- dict(key=value)
- dict(DICT)
- dict(iterable),其中iterable的每个元素必须是两元素的数据对象,例如
("one",1)
、["two",2]
- 后两种都可以结合第一种方式
- 使用dict对象的fromkey()方法
- 使用dict对象的copy()方法
- 字典解析的方式。
增删改查
检索不存在的key时会报错。但如果自己去定义dict的子类,那么可以自己重写__missing__()
方法来决定检索的key不存在时的行为。
1 | 'one': 1, 'two': 2, 'three': 3, 'four': 4} d = { |
get(key,default)方法检索dict中的元素,如果元素存在,则返回对应的value,否则返回指定的default值,如果没有指定default,且检索的key又不存在,则返回None。
1 | 'one': 1, 'two': 2, 'three': 3, 'four': 4} d = { |
**setdefault(key,default)**方法检索并设置一个key/value,如果key已存在,则直接返回对应的value,如果key不存在,则新插入这个key并指定其value为default并返回这个default,如果没有指定default,key又不存在,则默认为None。
**update(key/value)**方法根据给定的key/value对更新已有的键,如果键不存在则新插入。
**del D[KEY]**可以用来根据key删除字典D中给定的元素,如果元素不存在则报错。
**clear()**方法用来删除字典中所有元素。
**pop(key,default)**用来移除给定的元素并返回移除的元素。但如果元素不存在,则返回default,如果不存在且没有给定default,则报错。
**popitem()**用于移除并返回一个(key,value)
元组对,每调用一次移除一个元素,没元素可移除后将报错。在python 3.7中保证以LIFO的顺序移除,在此之前不保证移除顺序。
视图对象
- **keys()**返回字典中所有的key组成的视图对象;
- **values()**返回字典中所有value组成的视图对象;
- **items()**返回字典中所有(key,value)元组对组成的视图对象;
- **iter(d)**函数返回字典中所有key组成的可迭代对象。等价于
iter(d.keys())
视图对象中的数据会随着原字典的改变而改变。
集合
集合也是容器,其内元素都是无序、唯一、不可变的。它常用来做成员测试、移除重复数据、数据计算(比如交集、并集、差集)。
集合Set是dict的无value版。集合也使用大括号包围:
1 | 'a','b','c'} s = { |
1 | set("abcde") x = |
交集
&
或intersection()方法并集
|
或union()方法差集
-
或difference()还有XOR操作
^
,取集合1、集合2中非交集的部分
s1.isdisjoint(other_type)
测试集合和另一个数据容器(如集合、列表)是否存在相交数据。
基本操作
**s1.add(elem)**添加元素到集合s1中。因为集合中的元素都唯一,所以添加已存在的元素不会有任何效果,但也不会报错。
**s1.remove(elem)**移除集合s1中的元素。
**s1.pop()**随机移除一个元素并返回这个元素。
**s1.clear()**清空集合。
**s1.discard(elem)**移除已存在的某个元素,如果不存在则无视(返回None)。
**s1.copy()**拷贝(浅拷贝)集合s1。
**len(s1)**返回集合s1长度。
i in s1测试元素i是否在集合s1中。
编码
str是字符数据,bytes和bytearray是字节数据。它们都是序列,可以进行迭代遍历。str和bytes是不可变序列,bytearray是可变序列,可以原处修改字节。
bytes和bytearray都能使用str类型的通用函数,比如find()、replace()、islower()等,不能用的是str的格式化操作。所以,如有需要,参考字符串(string)方法整理来获取这些函数的使用方法。
单字节的字符(8bit位,共256个字符,ascii只用到了7个字节)能表示出来的字符毕竟有限,例如它没法表示出中文字符。所以,各国设计了各种多字节的字符编码来表达自己国家的文字,底层仍然使用二进制数存储,然后通过设计好的编码表将二进制数转换成各种字符。比如中国有GBK的各种编码,还有全球通用的编码类型unicode、utf-8、utf-16等。
无论什么编码,内部都包含ascii编码(也有例外,比如utf-16),它只需单个字节。也就是说,ascii编码是任何其它编码表的子集。但有些编码表强制规定每个字符占多少个字节(比如unicode固定为2个字节),有些编码表动态决定每个字符占多少个字节(比如utf-8是变长的,可能占用1-4个字节空间,存储字母为1个字节,存储中文字符为3个字节)。
关于unicode和utf-X格式的编码关系,粗略地可以认为utf-X是unicode格式的一种特殊类型。实际上在存储utf数据时,内部会自动在Unicode和utf之间进行转换。
在Python中字符数据也就是字符串,即str类型,字节数据也就是bytes类型或bytearray类型。
编码时,可以使用字节类型的构造方法bytes()、bytearray()来构造字节,也可以使用str类型的encode()方法来转换。
解码时,可以使用str类型的构造方法str()来构造字符串,也可以使用bytes、bytearray()类型的decode()方法。
另外需要注意的是,**编码和解码的过程中都需要指定编码表(字符集)**,默认采用的是utf-8字符集。
语法特性
见参考文章
函数
见参考文章
模块/包
见参考文章