基础

变量命名规则

  1. 变量名可以包括字母、数字和下划线。
  2. 变量名不能以数字开头。

获取用户输入

1
2
>>> x = input('x:')
x: 15

input()raw_input()的区别:
input()会假设用户输入的是合法的 Python 表达式。raw_input()会把所有的输入当作原始数据,然后将其放到字符串中。
Python3中,raw_input()被重命名为input().

注释# 或 ```

单行注释:# 右边的一切内容会被忽略
多行注释:多行注释

交互式窗口运行

运行Python程序还没有来得及看结果,程序窗口已经关闭,可以加入以下代码:

1
raw_input('Press <enter>')

计算

十六进制

1
2
>>> 0xAF
175

八进制

Python2 中八进制以00o开头,Python3 中八进制仅以0o开头。

1
2
3
4
>>> 010
8 # Python2
>>> 0o10
8 # Python3 and Python2

除法 /

1
2
3
>>> 1 / 2
>>> 0 # Python2
>>> 0.5 # Python3

Python2 的处理方法:

  1. 用至少一个实数(包含小数点)来进行运算 >>> 1.0/2.0
  2. 在程序前加上 from future import division

整除(地板除法) //

1
2
>>> 1 // 2
0

取余(模除) %

1
2
3
4
>>> 1 % 2
0
>>> 10 % 3
1

幂运算(乘方)**,pow(x,y[,z])

1
2
3
4
5
6
>>> 2 ** 3
8
>>> pow(2,3)
8
>>> pow(3,3,2)
1 # pow(3,3,2) 相当于 pow(3,3) % 2, 要比直接 pow(3,3) % 2 更快

绝对值 abs(x)

1
2
>>> abs(-10)
10

四舍五入 round(x[,n])

这是 Python 比较坑的一个函数,如果需要精度比较高的计算,这个函数很难 debug 。

该函数round(x[,n])中有两个参数,第一个是要进行处理的数字,第二个是要处理小数点后多少位,默认为None,即返回一个整数。 该函数的输出结果取决于两个因素:

  1. 被处理的数字是否能被精确存储;
  2. 你的 Python 版本。

先解释第一点。因为硬件的原因,浮点数在计算机中是以二进制表示的。但是大部分浮点数都不能精确地表示为二进制小数,所以在你用浮点数赋值时,精度已经丢失了。举个例子(Python2 和 Python3 相同),这个例子中3.6是没有被精确存储的:

1
2
>>> 4.0 - 3.6
0.3999999999999999

解决精确存储需要用到Decimal模块。并且注意在赋值时,用的是浮点数的字符串,并不是浮点数本身,因为在你用浮点数本身的时候,精度已经丢失。(Python2 和 Python3 相同)
1
2
3
>>> from decimal import Decimal
>>> Decimal('4.0') - Decimal('3.6')
Decimal('0.4')

再来聊第二点。在 Python2 的round(x[,n])方程说明中,该方程的描述就是我们所理解的四舍五入规则:官方描述:round()

1
2
3
4
The result is a floating point number. Values are rounded to the closest multiple of 10 to the power minus ndigits; 
if two multiples are equally close, rounding is done away from 0
结果会返回一个浮点数。结果会被约到离它最近的 10 的 -n 次方。
如果它和两个值距离相等,会被约到远离 0 的那个数。

举个栗子
1
2
3
4
5
6
7
8
9
10
11
>>> round(0.5)
1.0
>>> round(0.125, 2) # 0.125可以精确存储
0.13
>>> round(0.375, 2) # 0.375可以精确存储
0.38
>>> round(2.675, 2) # 因为2.675没办法精确存储
2.67
>>> from decimal import Decimal
>>> round(Decimal('2.675'),2) # 这种写法也是不对的,因为round函数的输入需要是浮点数,Decimal还是会转换成不精确的浮点数来作为输入
2.67

在 Python3 中,round(x[,n])变了,规则变成“四舍六入五平分”,也就是说如果末位是 5 的话,如果前一位是偶数则舍弃,如果是奇数则向前进一。再看一下官方说明:官方描述:round()
1
2
3
4
5
For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power minus ndigits; 
if two multiples are equally close, rounding is done toward the even choice (so, for example,
both round(0.5) and round(-0.5) are 0, and round(1.5) is 2).
这个函数也是会返回一个离它最近的 10 的 -n 次方。
但是当它和两个数字距离相同时,会被约到最近的偶数。

再举个栗子
1
2
3
4
5
6
7
8
9
10
11
>>> round(0.5)
0
>>> round(0.125, 2) # 0.125可以精确存储
0.12
>>> round(0.375, 2) # 0.375可以精确存储
0.38
>>> round(2.675, 2) # 同样因为2.675没办法精确存储
2.67
>>> from decimal import Decimal
>>> round(Decimal('2.675'),2) # 这次就是对的,因为 Python3 中round貌似可以接受Decimal,返回也是Decimal
Decimal('2.68')

所以在 Python2 和 Python3 中正确的四舍五入写法:

1
2
3
>>> from decimal import Decimal, ROUND_HALF_UP
>>> Decimal('2.675').quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)
Decimal('2.68')

向上/向下取整math.ceil(x)/math.floor(x)

该方程Python2和Python3的唯一区别是返回值的类型,举个栗子:

1
2
3
4
5
6
7
>>> import math
>>> math.ceil(3.67)
4 # Python3
4.0 # Python2
>>> math.floor(3.67)
3 # Python3
3.0 # Python2

开方math.sqrt(x)/cmath.sqrt()

复数的开放用cmath.sqrt(x),虚数单位用j来表示。Python2和Python3没有区别。

1
2
3
4
5
6
7
8
9
>>> import math. cmath
>>> math.sqrt(4)
2.0
>>> math.sqrt(4.0)
2.0
>>> cmath.sqrt(-4)
2j
>>> cmath.sqrt(-4.0)
2j

序列

Python 中包含 6 种内建的序列:list, tuple, string, Unicode string, buffer object, xrange object.

通用序列操作

索引:索引是从0开始的,-1是序列的最后一个元素。
分片:

  • 分片是通过冒号隔开的两个索引来实现。
  • 第一个索引是要提取的第一个元素的编号,最后一个索引是分片之后剩余部分的第一个元素的编号。所以,第一个索引的元素是包含在分片内的,而第二个,则不包含在分片内。
  • 分片中,如果最左边的索引比它最右边的晚出现在序列中,那结果就是一个空的序列。
  • 分片的步长默认为1,也可以是负数,但是不能为0。正步长,Python 会从序列的头部开始向右提取元素,直到最后一个元素。负步长,会从尾部开始向左提取元素,直到第一个元素。

成员资格:可以用in运算符,返回True or False
长度/最大/最小值: len(), max(), min()

zip函数:该函数可以将两个序列像拉链一样,拉在一起,然后返回一个元组的列表。zip函数可以用作用于任意多的序列,并且可以处理不等长的序列,当最短的序列用完的时候停止。

1
2
3
4
>>> a = [1,2,3]
>>> b = ['a','b','c']
>>> zip(a,b)
[(1,'a'),(2,'b'),(3,'c')]

enumerate函数:该函数可以在需要索引的时候提供序列的索引。

1
2
3
4
5
>>> a = ['a','b','c']
>>> for index, value in a: print(index, value)
0 a
1 b
2 c

sorted函数:该函数返回一个排好序的序列,并不修改原序列,而是返回一个排好序的版本。

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

reversed函数:该函数返回一个翻转的可迭代对象。
1
2
>>> list(reversed([3,4,1,2]))
[2,1,4,3]

列表 list

删除元素 del

1
2
3
4
>>> l = [1,2,3,4]
>>> del l[2]
>>> l
[1,2,4]

分片赋值

分片复制非常强大,能实现删除,插入等一些列操作。

1
2
3
4
>>> a = [1,2,3,4,5,6]
>>> a[3:] = [7]
>>> a
[1,2,3,7]

分片赋值实现插入:
1
2
3
4
>>> a = [1,2,3,4,5,6]
>>> a[1:1] = [1.1,1.2]
>>> a
[1,1.1,1.2,2,3,4,5,6]

分片复制实现删除:
1
2
3
4
>>> a = [1,2,3,4,5,6]
>>> a[1:4] = []
>>> a
[1,5,6]

列表方法

list.append(x)
在列表的末尾追加新的对象,不返回值,直接修改原来的列表。

list.count(x)
统计某个元素在列表中出现的次数。

list.extend(iterable)
在列表的末尾一次性追加另一个序列的多个值,是修改原有序列,并不是生成一个新的序列。

list.index(x[, start[, end]])
用于从列表中找出某个值第一个匹配项的索引位置。可选参数规定了 list 的寻找范围。但返回值仍是从整个 list 开始算起。

list.insert(i,x)
将对象插入列表中。

list.pop([i])
移除列表中的一个元素,默认是最后一个元素,并且返回该元素的值。

list.remove(x)
移除列表中某个值的第一个匹配项,修改了原有列表,但并不返回值。

list.reverse()
将列表中的元素反向存放,改变了列表,但是并不返回值。如果需要一个反向迭代,可以使用reversed函数,该函数返回一个反向迭代器。

list.sort(key=None, reverse=False)
该函数用于在原位置对列表进行排序,改变原有序列,但并不返回值。如果想要获得副本可以使用sorted()函数。key 参数可以规定比较的函数,比如长度len.

列表推倒式(轻量级循环)

该方法式利用其他列表创建新列表的一种方法,工作方式类似于for,并且也可以加入一个if语句添加到列表中,也可以增加更多的for语句。

1
2
>>> [x*y for x in range(4) for y in range(3) if x * y % 2 == 0]
[0, 0, 0, 0, 2, 0, 2, 4, 0, 6]

元组 tuple

元组不能修改。创建元组的方法非常简单,用逗号分隔一些值,就会自动创建元组。元组除了创建和访问之外,没有其他过多的操作。所以元组一般用来做映射中的键值,或者作为内建函数和方法的返回值存在。

字符串

字符串和元组一样都是不可变的。

字符串常量

string.digits
包含数字0-9的字符串
string.letters,在Python3中是string.ascii_letters
包含所有大小写字母的字符串
string.lowercase,在Python3中是string.ascii_lowercase
包含所有小写字母的字符串
string.printable
包含所有可打印字符的字符串
string.punctuation
包含所有标点的字符串
string.uppercase,在Python3中是string.ascii_uppercase
包含所有大写字母的字符串

值被转换成字符串的两种机制

str:会把值转换成合理形式的字符串

1
2
>>> print(str("hello"))
>>> hello

repr:会创建一个字符串,以合法的 Python 表达形式来表示值。在 Python2 中,repr() 也可以写成

1
2
3
4
>>> print(repr("hello"))
>>> 'hello'
>>> print`42` # Python2
>>> 42

长字符串

可以用三个引号代替普通引号,在三个引号内部可以同时使用单引号和双引号,而不需要使用反斜线进行转义。
普通字符串进行换行,可以在一行之中的最后一个字符加一个反斜线,这样换行符本身就被转义了。

1
2
3
>>> print("hello \
world")
>>> hello world

原始字符串

原始字符串以r开头,原始字符串不会把反斜线当作特殊字符,在原始字符串中的输入,每个字符都会和书写方式一致。原始字符串的最后一个字符不能是反斜线,如果最后一个字符是反斜线, Python 会不清楚是否应该结束字符串。

1
2
>>> print(r'C:\nowhere')
'C:\nowhere'

转义

使用反斜线对字符串重的符号进行转义。

1
2
>>> 'Let\'s go!'
"Let's go!"

字符串格式化%

字符串格式化通过百分号%来实现,在%左侧放置一个字符串,右侧放置希望被格式化的值。如果要在格式化字符串里面包括百分号,那么必须使用%%
如果右侧是元组的话,其中的每一个元素都会被单独格式化,每个值都需要一个对应的转换说明符。右侧可以放一个值,也可以是元组或者字典,但是如果使用列表或者其他序列,会被解释成一个值。

1
2
>>> 'Price is: $%d' % 42
'Price is: $42'

转换符说明:

  1. %字符:标记转换说明符的开始。
  2. 转换标志(可选):-表示左对齐;+表示在转换值之前要加上正负号; (空格)表示正数之前保留空格;0表示转换值若位数不够则用0填充。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> from math import pi
    >>> '%010.2f' % pi # 0
    '0000003.14'
    >>> '%-010.2f' % pi # -
    '3.14 '
    >>> '% 10.2f' % pi # 空格
    ' 3.14'
    >>> '%+10.2f' % pi # +
    ' +3.14'
  3. 最小字段宽度(可选):转换后的字符应该需有该值指定的宽度,如果是*,则宽度会从元组中读出。

  4. 点(.)后跟精度值(可选):如果转换的是实数,精度值就表示出现在小数点后的位数,如果转换的是字符串,该数字表示的最大字段宽度。如果是*,那么精度将会从元组中读出。
    字段宽度和精度都是整数,并且通过.分隔,如果只有精度,也需要.

    1
    2
    >>> '%+*.*f' % (10,2,pi)
    ' +3.14'
  5. 转换类型:
    |转换类型|含义|
    |-:|-:|
    |d,i|带符号的十进制整数|
    |o|不带符号的八进制|
    |u|不带符号的十进制|
    |x/X|不带符号的十六进制|
    |e/E|科学计数法表示的浮点数|
    |f/F|十进制浮点数|
    |g/G|如果指数大于-4或者小于精度值则和e相同,其他情况与f/F相同|
    |C|单字符(接受整数或者单字符字符串)|
    |r|字符串(使用repr转换任意Python对象|
    |s|字符串(使用str转换任意Python对象|

字符串常用方法

string.find(s, sub[, start[, end]])
在长字符串中寻找子串,返回子串所在位置的最左端索引。没有找到则返回-1。也可以规定寻找范围的起始点和结束点。
string.join(words[, sep])
用来连接序列中的元素

1
2
>>> '+'.join(['1','2','3','4','5'])
'1+2+3+4+5'

string.lower(s)
返回字符串的小写字母版本。另外还有两个函数用来给单词的首字母进行大写:string.title()string.capwords(),两者有细微的区别:

1
2
3
4
>>> "that's all forks".title()
"That'S All Forks"
>>> string.capwords("that's all forks")
"That's All Forks"

string.replace(s, old, new[, maxreplace])
该方法返回某字符串的所有匹配项均被替换之后得到的字符串。
string.split(s[, sep[, maxsplit]])
该方法用来分割字符串,如果不提供分隔符,程序会把所有的空格作为分隔符(空格,制表,换行等)
string.strip(s[, chars])
该方法会去除两侧(不包括内部)空格的字符串。也可以去掉指定的分隔符,不过注意,该方法只会去除两侧的字符。
string.translate(s, table[, deletechars])
该方法也是替换字符串中的某些部分,但是只会处理单个字符,某些时候效率比string.replace(s, old, new[, maxreplace])高。该函数的第二个参数是可选的,用来指定需要删除的字符。
使用该方法需要用到另外一个函数,string.maketrans(),该函数接受两个等长的字符串,表示第一个字符串中的每个字符都用第二个字符串中相同位置的字符替换。该函数实际上是一张256个字符长度的表。

1
2
3
4
>>> from string import maketrans
>>> table = maketrans('cs','kz')
>>> len(table)
256

创建好这张表之后,可以将它用作string.translate(s, table[, deletechars])方法的参数,转换方法如下:

1
2
3
4
>>> from string import maketrans
>>> table = maketrans('cs','kz')
>>> 'this is an incredible test'.translate(table)
'thiz iz an inkredible tezt'

字典

字典是由多个键值对组成,每个键值对称作项。每个键和它的值之间用冒号隔开,项之间用逗号隔开。字典中的健是唯一的,而值并不惟一。
字典中的键可以为任意不可变类型,比如浮点型,字符串或者元组。
字典中的项是没有顺序的。

字典的基本操作

len(d):返回字典d中项的数量
d[k]:返回关联到键k上的值
d[k] = v:将v关联到键k
del d[k]:删除键为k的项
k in d:检查d中是否含有键为k的项。在字典中检查键的成员资格比在列表中检查值的成员资格更高效,数据结构的规模越大,两者的效率差距越明显。

字典的格式化字符串

字典的格式化字符串需要在每个转换说明符中的%字符后面,加上用圆括号扩起来的键,然后再跟上其他说明符。

1
2
3
>>> d = {'a':1,'b':2,'c':3}
>>> print('Hello, %(a)s.' % d)
'Hello, 1.'

字典的常用方法

dictionary.clear()
清除字典中所有的项,改变原有字典,并且没有返回值。
注意以下两种清除字典方法的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 第一种方法,赋值一个空的字典
>>> x = {}
>>> y = x
>>> x = {'name':'Gumby'}
>>> y
{'name':'Gumby'}
>>> x = {}
>>> y
{'name':'Gumby'}

# 第二种方法,clear()
>>> x = {}
>>> y = x
>>> x = {'name':'Gumby'}
>>> y
{'name':'Gumby'}
>>> x.clear()
>>> y
{}

dictionary.copy()
该方法返回一个具有相同键值对的新字典,该方法是浅复制(Shallow Copy),也就是说替换副本中的值的时候,原始字典并不受影响,但是如果原地修改某个值,原始字典也会改变。看个例子:

1
2
3
4
5
6
7
8
>>> x = {'username':'admin', 'machines':['foo','bar','baz']}
>>> y = x.copy()
>>> y['username'] = 'mlh'
>>> y['machines'].remove('bar')
>>> x
{'username':'admin', 'machines':['foo','baz']}
>>> y
{'username':'mlh', 'machines':['foo','baz']}

避免这个函数的方法是,使用深复制(Deep Copy),复制其包含的所有值。

1
2
3
4
5
6
7
8
9
10
>>> from copy import deepcopy
>>> d = {}
>>> d['name'] = ['A','B']
>>> d_copy = d.copy()
>>> d_deepcopy = deepcopy(d)
>>> d['name'].append('C')
>>> d_copy
{'name':['A','B','C']}
>>> d_deepcopy
{'name':['A','B']}

dictionary.fromkeys()
该方法使用给定的键,来建立新的字典,每个键都对应一个默认的值None

1
2
>>> dict.fromkeys(['name','age'])
{'name':None, 'age':None}

也可以自己提供默认值:

1
2
>>> dict.fromkeys(['name','age'],'(unknown)')
{'name':'(unknown)', 'age':'(unknown)'}

dictionary.get()
该方法是个宽松的访问字典项的方法,用该方法访问不存在的项时不会报错,会返回None。也可以自己定义返回值。

1
2
3
4
5
>>> d = {}
>>> print(d.get('name'))
None
>>> print(d.get('name', 'N/A'))
'N/A'

dictionary.has_key()
该方法可以检查字典中是否有特定的键,返回True or False

1
2
3
>>> d = {}
>>> d.has_key('name')
False

dictionary.items()
该方法将字典中的所有项以列表的形式返回,列表中的每一项都表示为(key, value)对的形式,返回时没有特定的次序。

1
2
3
>>> d = {'name':'Tom', 'age':13}
>>> d.items()
[('name', 'Tom'), ('age', 13)]

dictionary.iteritems()
该方法与dictionary.items()大致相同,但是会返回一个迭代器对象,并不是列表。
dictionary.keys()
该方法将字典所有的键以列表形式返回。
dictionary.iterkeys()
该方法返回针对键的迭代器。
dictionary.values()
该方法将所有的值以列表的形式返回。
dictionary.itervalues()
该方法返回针对值的迭代器。
dictionary.pop()
该方法获得给定的键的值,并且将这个键值对从字典中移除。

1
2
3
4
5
>>> d = {'A':1,'B':2}
>>> d.pop('A')
1
>>> d
{'B':2}

dictionary.popitem()
该方法谈随机返回一个项,并且在字典中删除该项。
dictionary.setdefault()
该方法与dictionary.get()类似,获得与给定键相关联的值,如果不存在,会返回默认值,并以默认值更新字典。如果存在,就返回对应的值,但不改变字典。默认值默认为None

1
2
3
4
5
6
7
8
9
10
11
>>> d = {}
>>> d.setdefault('name','N/A')
'N/A'
>>> d
{'name':'N/A'}
>>> d['name'] = 'Tom'
>>> d.setdefault('name','N/A')
'Tom'
>>> d
{'name':'Tom'}

dictionary.update()
该方法可以利用一个字典项更新另外一个字典。相同的键会对值进行覆盖。

1
2
3
4
5
>>> d = {'A':1, 'B':2}
>>> e = {'B':4, 'C':9}
>>> d.update(e)
>>> d
{'A':1, 'B':4, 'C':9}

其他

交互式解释器

在交互式解释器中使用if语句,需要按两次回车,if语句才能执行。

nan 是一个特殊值的简写,意思是’not a number’(非数值)

同一性运算符is

该运算符是用来判断两个变量是否绑定同一数据结构中,两个变量的值相等,不等于被绑定在同一数据结构中。另外要避免将is运算符用在类似数值和字符串这类不可变值,会出现不可预测的结果。

1
2
3
4
5
6
7
8
9
10
>>> x = y = [1,2,3]
>>> z = [1,2,3]
>>> x == y
True
>>> x == z
True
>>> x is y
True
>>> x is z
False

断言assert

该语句主要用来判断某个条件是否为真,如果否,则报错终止程序。经常用来检查函数参数的属性,或者用来作为初期测试和调试过程中的辅助条件。在语句的条件后可以添加字符串,用来解释断言。

1
2
3
4
5
6
7
8
9
10
11
12
>>> a = 1
>>> assert a > 0
>>> assert a > 2
Traceback (most recent call last):
File "main.py", line 1, in <module>
assert a > 2
AssertionError
>>> assert a > 2, 'a should be larger than 2'
Traceback (most recent call last):
File "main.py", line 1, in <module>
assert a > 2
AssertionError: a should be larger than 2

exec

该语句是用来执行字符串中的代码

future 模块是什么