python入门
流畅的py-读书笔记
数据结构
list & tuple
- 列表推导
等价于symbols = 'ABCD' codes = [] for symbol in symbols: codes.append(ord(symbol))
symbols = 'ABCD' codes = [ord(symbol) for symbol in symbols]
其实, 这里有变量泄露的问题, 这个时候symbol会泄露到全局
也可以这样子, 习惯了js的,其实感觉更喜欢这样子写
symbols = 'ABCD'
codes = map(ord, symbols)
其实开始没想到字符串也可以for, 阔以map
Python 会忽略代码里 []、 {} 和 () 中的换行, 一行太长的时候可以把一行拆成多行写
emmmmmmm~, 但是如果有条件的话,比如
symbols = 'ABCD'
codes = [ord(symbol) for symbol in symbols if ord(symbol) > 127]
等价到filter
和map
后, 就要用lambda表达式,像这样子
symbols = 'ABCD'
codes = filter(lambda c: c > 127, map(ord, symbols)))
列表推导还可以是二维的
>>> [char+num for char in 'ABCD' for num in '1234']
- 生成器表达式
上面第一个是列表推导产生了一个列表,又拿列表初始化了一个tuple>>> codes1 = tuple([ord(symbol) for symbol in symbols]) >>> codes1 = tuple(ord(symbol) for symbol in symbols)
而下面这个就是叫生成器表达式…因为tuple()
这已经有了圆括号,所以这里省去了生成器表达式两边的括号
生成器表达式和列表推导不同的是一次产生一个元素, 表达上两边圆括号代替方括号
tuple
tuple和list都能存放不同类型的元素, 除此外还有collections.deque也可以的
与list不同, tuple是不可变的
常见用法
>>> print '[*]%d %d' % (1, 2)
交换两数字
>>> a, b = b, a
元祖拆包-元祖前加上*, 可以拆包作为函数参数
>>> ord(*('A', ))
可以方便函数返回多个值, 然后一拆包…
collections.namedtuple
带字段名的tuple…>>> from collections import namedtuple >>> Person = namedtuple('Person', ['firstName', 'lastName']) >>> haibin = Person('hai', 'bin') >>> haibin.firstName 'hai'
切片
list, tuple, str等支持切片操作
基本操作 [a:b:c], 其中c是步长,如果是负数,就是倒着来的
>>> haibin[::]
'haibin'
>>> haibin[::1]
'haibin'
>>> haibin[::-1]
'nibiah'
所以[::-1]
可以实现Reverse的效果
注意的点是:
切片和区间操作不包括区间最后一个元素(即右边界), str[: 2] 是 不包括 str[2]的
比如
>>> range(10) == range(0, 10)
True
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
这个range不包括右边界10…
切片赋值
直接贴书上的例子
>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[2:5] = [20, 30]
>>> l
[0, 1, 20, 30, 5, 6, 7, 8, 9]
>>> del l[5:7]
>>> l
[0, 1, 20, 30, 5, 8, 9]
>>> l[3::2] = [11, 22]
>>> l
[0, 1, 20, 11, 5, 22, 9]
>>> l[2:5] = 100
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable
>>> l[2:5] = [100]
>>> l
[0, 1, 100, 22, 9]
等号右边必须是可迭代对象,即便只有一个元素
sort
list.sort 对原list排序,返回None
sorted 不改变原来的对象, 返回新list>>> l = [1, 2, 4, 3] >>> l.sort() >>> l [1, 2, 3, 4]
array
数组, 处理较大数据,只能存储同一类型的, 看起来就比较底层比较快
大数据处理还会用到NumPy
和SciPy
库, 准备用到的时候再去学collections.deque
列表常常用来存一些相同类型的元素, 像是数组
而元祖更像是字段表的感觉,常存一些不同类型的
dict
py里可映射类型都是dict实现的
dict是{key: value}
形式, 要求key
是可散列数据结构
可散列数据结构
- 在对象生命周期里,他的散列值不变
- 对象要实现hash()方法
- 要有qe()方法
python里的不可变类型是可散列数据结构, 对于tuple
, 要tuple
包含的所有元素都是不可变类型的时候他才算是可散列的
>>> hash((1, 2, 3))
2528502973977326415
>>> hash((1, [2, 3]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
创建dict
>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> a == b == c == d == e
True
dict也能够推倒(ノ*・ω・)ノ,ahhh)
set
集合可以用于去重, 这操作…
>>> list(set([1,2,3,4,1,2,3]))
[1, 2, 3, 4]
另外set的元素要是可散列的
set本身是不可散列的
但…frozenset可以散列
所以set里不能包含set, 但可以包含emmmm, frozenset
集合操作
|
并集&
交集-
差集
集合字面量{1, 2, 3}
, 空集是set()
, 而不能写成{}
, 因为{}
是空的dict
集合也能推倒…
dict & set 和 散列表
dict 和 set很快, 因为他们背后是散列表
set其实大概相当于是只有key
的一个dict,(或者叫做不关注其value
)
我还以为里面是树实现的…C++ 里map应该是树实现的吧
树来实现的话应该会比单纯的稀疏散列表要省下很多内存…
书中也提到了python字典在内存的开销上巨大
不过散列表以空间换时间, 是不是查询比树要快
散列表查询是直接线性的复杂度, 算是O(1)…?
如果这样子的话…那真的是快…
总结一下,这个字面量
[1, 2, 3] # list
(1, 2, 3) #tuple
(1, ) # tuple
(1) # 就是1, 数字
{1: 1, 2: 2} # dict
{} # dict
{1, 2, 3} # set
字符
二进制序列类型
- bytes 不可变
- bytearray 可变
试验了下…这个东西对py2的支持不太好, py2还是str比较常用
字面量形式是b'somestr'
, 下面都来自py3
>>> bytes.fromhex('31 32 33 34')
b'1234'
处理二进制数据常用struct和memoryview
在py2里, 看起来这个bytes
是str
接管了
>>> type(base64.b64encode('abc'))
<type 'str'>
>>> type(base64.b64encode(b'abc'))
<type 'str'>
在py3里, 这里才出现了bytes
>>> type(base64.b64encode('abc'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/base64.py", line 59, in b64encode
encoded = binascii.b2a_base64(s)[:-1]
TypeError: a bytes-like object is required, not 'str'
>>> type(base64.b64encode(b'abc'))
<class 'bytes'>
编码 解码
编码encode: 字节序列 -> 文本字符串
解码decode: 文本字符串 -> 字节序列
emmmmmm…. 这个在py2有点迷
py3的话
encode只存在于str
, 即为bytes str.encode(args)
decode只存在于bytes
, 即为str bytes.decode(args)
>>> 'a'.encode('utf8')
b'a'
# encode: str -> bytes
>>> b'a'.decode('utf8')
'a'
# decode: bytes -> str
而且.这个args只能是text encode
, 不能是hex
之类的….
另外, 一般的比如utf-8有很多别名可以用: utf8
, utf_8
, utf-8
, U8
现在没网..不过估计..应该是py2这一块比较混乱, 所以py3把encode, decode这一块功能单一化了
根据错误提示…应该是是放到codecs.decode
和codecs.encode
了
py2 默认编码是ascii, py3默认编码是utf8
先跳过这一块…这…感觉文本处理, 还是推荐使用py3的感觉
开始是用help('str')
来找到encode
和decode
的帮助…然后才发现这样子更好
>>> print ''.encode.__doc__
S.encode([encoding[,errors]]) -> object
Encodes S using the codec registered for encoding. encoding defaults
to the default encoding. errors may be given to set a different error
handling scheme. Default is 'strict' meaning that encoding errors raise
a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and
'xmlcharrefreplace' as well as any other name registered with
codecs.register_error that is able to handle UnicodeEncodeErrors.
我蠢了…
>>> help(''.encode)
这样子help得到的结果好像是就是__doc__
过来的
闭包
抄书上的一个例子
def make_averager():
series = []
def averager(new_value):
series.append(new_value)
total = sum(series)
return total/len(series)
return averager