python入门
Extious

写在前面:本文基于Python 3.x

基础数据类型

数值类型

python中只有以下几种类型

1
2
3
4
5
6
7
   类型           示例
---------------------------------------
整数 1234, -24, 0
浮点数 1.23, 1., .2, 3.14e-10
八进制 0o177, 0O177
十六进制 0x9ff, 0X9ff
二进制 0b1010, 0B1010

注意:

  • 整数无穷精度
  • 浮点数精度和C语言中的双精度浮点数相同
  • 数值类型为不可变对象,值改变之后会创建新内存

运算

支持最基本的数学运算符号:+ - * / % **、取正负+x -x,地板除法//,除法和取模divmod(x, y)

1
2
>>> divmod(5, 2)
(2, 1)
  • **:次方
  • //:地板除法
  • math.ceil()天花板运算
  • ‘+’和’*’也能处理字符串

除了上面的基础算术运算符,还支持很多数值类型的运算符,例如:取反(~)、位移(>>)、位与(&)、位异或(^)、逻辑与(and)、逻辑或(or)

还有一些内置数学函数:

1
2
3
4
5
6
7
8
9
pow():求幂,如pow(2,3)=8
abs():求绝对值,如abs(-3)=3
round():四舍五入,如round(3.5)=4
int():取整(截去小数部分),如int(3.5)=3
float():转换成浮点数,如float(3)=3.0
oct():十进制整数转换成八进制
hex():十进制整数转换成十六进制整数
bin():十进制整数转换成二进制
...等等...

对于小数和分数有相应的模块:decimal、fraction

注意,不能用==和!=进行浮点数比较;逻辑and、or返回的是表达式的值而不是bool

布尔类型

  • python中bool类型是int类型的一个子类
  • python中的任何一个数据对象要么是True,要么是False
1
2
3
4
5
6
7
8
9
          True                 False
----------------------------------
number: 11.1 00.0
string: 'a' ''
None: None
list: ['a']、[1] []
[0]、['']、[None]
Set/Dict: {'a'} {}
tuple: ('a')、(1) ()、('')、(0)、(None)

None是一种特殊的数据对象,像数值1、字符串’a’一样,只不过内存中这个数据对象里面存储的数据是我们不得而知的,但它永远表示为False

1
2
3
4
5
6
>>> 2 or 3,3 or 2
(2, 3)
>>> [] or 3
3
>>> [] or {}
{}

再次说明,and、or返回的不是True/False的布尔值,而是逻辑表达式的运算结果。

等值比较

在python中,只要两个对象的类型相同,且它们是内置类型(字典除外),那么这两个对象就能进行比较== != < <= > >=

1
2
>>> bool([1,2,[3,3]] < [1,2,[3,4]])
True

字符串也可以进行比较

1
2
>>> "ac" > "ab" < "ad"
True

None对象只能参与等值和不等值比较

1
2
3
4
5
6
7
8
>>> None == None
True
>>> None != None
False
>>> None <= None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<=' not supported between instances of 'NoneType' and 'NoneType'

python支持连续比较,连续比较时等价于使用and运算

注意:is比较的是内存对象;而==比较的是值

字符串

字符串为不可改变对象

字符串常量

python中可以使用单引号、双引号、三引号包围字符串,并可以使用反斜线转义特殊字符:

  • 单、双引号是完全一致的,不像其他语言一样有强、弱引用之分
  • 三引号('''xxx'''"""xxx""")包围的字符完全是字面符号,包围什么就得到什么,包括换行,且不会进行任何转义、替换等
    • 使用这种块字符串的方式,在输入需要换行的字符串时非常方便
    • 而且可以作为块注释符注释一段代码。这表示这段被包围的代码解释为字符串,但因为没有赋值给变量,所以直接丢弃了
  • 反斜线\可以转义特殊字符,例如在字符串中保留单引号"a\'b"

但是python在输出字符串的时候,总是倾向于使用单引号,除非字符串中包含了单引号。对于那些非打印字符,将总是使用十六进制的方式输出。

1
2
3
4
5
6
7
>>> '''aaaa
... aaa
... '''
'aaaa\naaa\n'

>>> '\001' # 二进制字符,十六进制格式输出
'\x01'

也可以使用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
2
3
4
5
6
7
8
9
10
>>> who1 = "long"
>>> who2 = "shuai"
>>> "hello %s world" % "your"
'hello your world'
>>> "hello %s world" % who1
'hello long world'
>>> "hello %s world" % (who1)
'hello long world'
>>> "hello %s %s world" % (who1, who2)
'hello long shuai world'

可以使用字典索引

1
2
>>> "%(name1)s with %(name2)s" % {"name1":"longshuai", "name2":"xiaofang"}
'longshuai with xiaofang'

也可以使用format()来格式化字符串时,使用在字符串中使用{}作为占位符,占位符的内容将引用format()中的参数进行替换。可以是位置参数、命名参数或者兼而有之。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 位置参数
>>> template = '{0}, {1} and {2}'
>>> template.format('long','shuai','gao')
'long, shuai and gao'

# 命名参数
>>> template = '{name1}, {name2} and {name3}'
>>> template.format(name1='long', name2='shuai', name3='gao')
'long, shuai and gao'

# 混合位置参数、命名参数
>>> template = '{name1}, {0} and {name3}'
>>> template.format("shuai", name1='long', name3='gao')
'long, shuai and gao'

也有内置函数format()

1
2
3
4
5
6
7
8
>>> '{0:.2f}'.format(1.2345)
'1.23'

>>> format(1.2345, '.2f')
'1.23'

>>> '%.2f' % 1.2345
'1.23'

字符串方法

参考文章

列表

列表类型是一个容器,它里面可以存放任意数量、任意类型的数据。

1
>>> L = [[1, 2, 3], "a", "b", [4, "c"]]

列表是可变对象

image

上面是L = ["a", "b", "c"]列表的图示。变量名L存储了列表的内存地址,列表内部包含了类型声明、列表长度等元数据,还保存了属于列表的3个元素的内存地址。需要注意的是,列表元素不是直接存在列表范围内的,而是以地址的形式保存在列表中

列表构造

有两种常用的构造列表方式:

  1. 使用中括号[]
  2. 使用list()构造方法

使用(中)括号构建列表时,列表的元素可以跨行书写,这是python语法中各种括号类型的特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> []     # 空列表

>>> [1,2,3]
[1, 2, 3]

>>> L = [
1,
2,
3
]

>>> list('abcde')
['a', 'b', 'c', 'd', 'e']

>>> list(range(0, 4))
[0, 1, 2, 3]

列表支持+ * += 符号操作和切片索引等序列操作

sort()是列表类型的方法,只适用于列表;sorted()是内置函数,支持各种容器类型。

迭代和解析

列表是一个序列,可以使用in测试,使用for迭代。

1
2
3
4
5
6
7
8
9
10
11
>>> L = ["a","b","c","d"]
>>> 'c' in L
True

>>> for i in L:
... print(i)
...
a
b
c
d

列表解析,它指的是对序列中(如这里的列表)的每一项元素应用一个表达式,并将表达式计算后的结果作为新的序列元素(如这里的列表)。

1
2
>>> [ i for i in "abcdef" ]
['a', 'b', 'c', 'd', 'e', 'f']

元组

元组和列表一样,都是容器型的数据结构,且都是序列,所以容器中的元素都是按照索引位置有序存放的。所以,可以进行索引取值、切片等序列通用操作。

不同的是,元组是不可变序列,无法原处修改,意味着修改元组必须创建新的元组对象。

image

构造

1
2
3
4
5
6
7
8
>>> (1,2,3,4)
(1, 2, 3, 4)

>>> tuple("abcdef")
('a', 'b', 'c', 'd', 'e', 'f')

>>> tuple([1,2,3,4])
(1, 2, 3, 4)

元组中可以嵌套任意类型的数据对象。

操作

元组支持+ *符号操作、可以通过+=的方式进行二元赋值

因为元组是不可变对象,所以可以使用hash()进行hash:

1
2
3
4
5
6
7
8
>>> hash(T)
-1883319094
>>> hash((1,2,3))
-378539185
>>> hash([1,2,3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

因为元组是不可变对象,所以没有直接方法修改元组,只能通过其它手段根据原始元组间接地构造新元组。切片返回的元组也是一种修改方式。

字典

dict是一个hashtable数据结构,除了数据类型的声明头部分,还主要存储了3部分数据:一个hash值,两个指针。

这个hash值是根据key运用内置函数hash()来计算的,占用8字节(64位机器)。除了hash值,后面两个是指针,这两个指针分别是指向key、指向value的指针,每个指针占用一个机器字长,也即是说对于64位机器各占用8字节,所以一个dict的元素,除了实际的数据占用的内存空间,还额外占用24字节的空间。

image

对比列表

python中list是元素有序存储的序列代表,dict是元素无序存储的代表。它们都可变,是python中最灵活的两种数据类型。

但是:

  • dict的元素检索、增删改速度快,不会随着元素增多、减少而改变。但缺点是内存占用大

  • list的元素检索、增删改速度随着元素增多会越来越慢(当然实际影响并没有多大),但是内存占用小

换句话说,dict是空间换时间,list是时间换空间。

构造

有几种构造字典的方式:

  1. 使用大括号包围
  2. 使用dict()构造方法,dict()构造有3种方式:
    • dict(key=value)
    • dict(DICT)
    • dict(iterable),其中iterable的每个元素必须是两元素的数据对象,例如("one",1)["two",2]
    • 后两种都可以结合第一种方式
  3. 使用dict对象的fromkey()方法
  4. 使用dict对象的copy()方法
  5. 字典解析的方式。

增删改查

检索不存在的key时会报错。但如果自己去定义dict的子类,那么可以自己重写__missing__()方法来决定检索的key不存在时的行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> d = {'one': 1, 'two': 2, 'three': 3, 'four': 4}

>>> class mydict(dict):
... def __missing__(self, key):
... return None
...

>>> dd = mydict(d)
>>> dd
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> dd["ten"]
>>> print(dd["ten"])
None

get(key,default)方法检索dict中的元素,如果元素存在,则返回对应的value,否则返回指定的default值,如果没有指定default,且检索的key又不存在,则返回None。

1
2
3
4
5
6
7
>>> d = {'one': 1, 'two': 2, 'three': 3, 'four': 4}

>>> d.get("two")
2

>>> d.get("six","not exists")
'not exists'

**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
2
3
>>> s = {'a','b','c'}
>>> type(s)
<class 'set'>
1
2
3
4
5
6
7
>>> x = set("abcde")
>>> y = set("defgh")
>>> z = set("opq")
>>> x
{'b', 'e', 'c', 'a', 'd'}
>>> y
{'e', 'h', 'f', 'g', 'd'}
  • 交集&或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之间进行转换。

image

在Python中字符数据也就是字符串,即str类型,字节数据也就是bytes类型或bytearray类型。

编码时,可以使用字节类型的构造方法bytes()、bytearray()来构造字节,也可以使用str类型的encode()方法来转换

解码时,可以使用str类型的构造方法str()来构造字符串,也可以使用bytes、bytearray()类型的decode()方法

另外需要注意的是,**编码和解码的过程中都需要指定编码表(字符集)**,默认采用的是utf-8字符集。

语法特性

见参考文章

函数

见参考文章

模块/包

见参考文章

参考文章

骏马金龙的博客

由 Hexo 驱动 & 主题 Keep
总字数 39.4k 访客数 访问量