《Intermediate Python》阅读笔记 下半部分
容器 Collections
- 一个模块 
- defaultdict:当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19- from collections import defaultdict 
 dict = defaultdict( factory_function) # 可以是list、set、str等,当key不存在时,返回工厂函数的默认值——[],(),'',0等
 colours = ( ('Yasoob', 'Yellow'),
 ('Ali', 'Blue'),
 ('Arham', 'Green'),
 ('Ali', 'Black'),
 ('Yasoob', 'Red'),
 ('Ahmed', 'Silver'),
 )
 favourite_colours = defaultdict(list)
 for name, colour in colours:
 favourite_colours[name].append(colour)
 # defaultdict(<type 'list'>,
 # {'Arham': ['Green'],
 # 'Yasoob': ['Yellow', 'Red'],
 # 'Ahmed': ['Silver'],
 # 'Ali': ['Blue', 'Black']
 # })
- counter:适用于需要使用dict和次数的场景,传入迭代器 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20- from collections import Counter 
 colours = ( ('Yasoob', 'Yellow'),
 ('Ali', 'Blue'),
 ('Arham', 'Green'),
 ('Ali', 'Black'),
 ('Yasoob', 'Red'),
 ('Ahmed', 'Silver'),
 )
 favs = Counter(name for name, colour in colours)
 ## Counter({
 ## 'Yasoob': 2,
 ## 'Ali': 2,
 ## 'Arham': 1,
 ## 'Ahmed': 1
 ## })
 c = Counter(a=3, b=1)
 d = Counter(a=1, b=2)
 c + d # 相加
 #Counter({'a': 4, 'b': 3})
- deque:双端队列,可以从头/尾两端添加或删除元素 - 1 
 2
 3
 4
 5- from collections import deque 
 d = deque()
 d = deque(range(5))
 d.popleft() # 输出: 0
 d = deque(maxlen=30) # 限制列表⼤⼩,当超出限制,数据会从队列另⼀端被挤出
- nametuple:像字典(dict)⼀样访问namedtuples,但namedtuples不可变 - 1 
 2
 3
 4
 5- from collections import namedtuple 
 Animal = namedtuple('Animal', 'name age type')
 perry = Animal(name="perry", age=31, type="cat")
 # Animal(name='perry', age=31, type='cat')
 print(perry.name) # 'perry'
枚举 Enumerate
- 内置函数 
- 遍历数据并⾃动计数 - 1 
 2
 3
 4
 5
 6
 7- for counter, value in enumerate(some_list): 
 print(counter, value)
 
 # 输出
 (0, ...)
 (1, ...)
 ...
- 定制从其他数字开始枚举 - 1 - enumerate(my_list, 1) # 从1开始枚举 
对象自省
- 运⾏时判断⼀个对象的类型的能⼒ 
- dir - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- my_list = [1, 2, 3] 
 dir(my_list) # 返回⼀个列表对象的所有⽅法名
 # Output: ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
 # '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
 # '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__',
 # '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
 # '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__',
 # '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__',
 # '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop',
 # 'remove', 'reverse', 'sort']
- type与id:type函数返回⼀个对象的类型,id函数返回任意不同种类对象的唯⼀ID - 1 
 2
 3
 4
 5- print(type('')) 
 # Output: <type 'str'>
 name = "Yasoob"
 print(id(name))
 # Output: 139972439030304
推导式
- 列表推导式 - 1 - variable = [out_exp for out_exp in input_list if out_exp == 2] 
- 字典推导式:类似列表推导式 - 1 
 2
 3
 4
 5
 6
 7
 8- mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3} 
 # 同⼀个字母但不同⼤⼩写的值合并
 mcase_frequency = {
 k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()
 }
 # 对换键值
 {v: k for k, v in some_dict.items()}
- 集合推导式:使用大括号的”列表推导“ - 1 - squared = {x**2 for x in [1, 1, 2]} 
异常
- try/except从句 
- 处理多个异常 - 把所有可能发⽣的异常放到⼀个元组⾥ - 1 
 2
 3
 4- try: 
 file = open('test.txt', 'rb')
 except (IOError, EOFError) as e:
 print("An error occurred. {}".format(e.args[-1]))
- 对每个单独的异常在单独的except语句块中处理 
- 捕获所有异常 - 1 
 2
 3
 4
 5- try: 
 file = open('test.txt', 'rb')
 except Exception:
 # 打印⼀些异常⽇志,如果你想要的话
 raise
 
- Finally从句:代码不管异常是否触发都将会被执⾏ 
- try/else从句 :在没有触发异常的时候执⾏⼀些代码 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- try: 
 print('I am sure no exception is going to occur!')
 except Exception:
 print('exception')
 else:
 # 这⾥的代码只会在try语句⾥没有触发异常时运⾏,
 # 但是这⾥的异常将 *不会* 被捕获
 print('This would only run if no exception occurs. And an error here ' 'would NOT be caught.')
 finally:
 print('This would be printed in every case.')
lambda表达式
- 是一行函数 
- lambda 参数:操作(参数) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- add = lambda x, y: x + y 
 print(add(3, 5))
 # 列表排序
 a = [(1, 2), (4, 1), (9, 10), (13, -3)]
 a.sort(key=lambda x: x[1])
 # Output: [(13, -3), (4, 1), (1, 2), (9, 10)]
 # 列表并行排序
 data = zip(list1, list2)
 data.sort()
 list1, list2 = map(lambda t: list(t), zip(*data))
一行式
- 简易Web Server :通过⽹络快速共享⽂件;在共享文件目录下的命令行输入 - 1 - $ python -m http.server 
- 规范的打印:规范打印出列表和字典 - 1 
 2
 3- from pprint import pprint 
 my_dict = {'name': 'Yasoob', 'age': 'undefined'}
 pprint(my_dict)
- 脚本性能分析:定位脚本中的性能瓶颈 - 1 - $ python -m cProfile my_script.py 
- csv转为json - 1 - $ python -c "import csv,json;print json.dumps(list(csv.reader(open('csv_file.csv'))))" 
- 列表展平 - 1 
 2
 3
 4- from itertools import itertools.chain.from_iterable 
 a_list = [[1, 2], [3, 4], [5, 6]]
 print(list(itertools.chain.from_iterable(a_list)))
 # Output: [1, 2, 3, 4, 5, 6]
For else
| 1 | for item in container: | 
使用C扩展
ctypes模块
- 提供了和C语⾔ 兼容的数据类型和函数来加载dll⽂件 
- 示例 - C代码: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 int add_int(int, int);
 float add_float(float, float);
 int add_int(int num1, int num2){
 return num1 + num2;
 }
 float add_float(float num1, float num2){
 return num1 + num2;
 }
- 编译为.so文件(windows下为DLL) - 1 
 2
 3
 4
 5
 6- #For windows 
 gcc -shared -o Test.dll Test.c
 #For Linux
 $ gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c
 #For Mac
 $ gcc -shared -Wl,-install_name,adder.so -o adder.so -fPIC add.c
- python中调用 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- from ctypes import * 
 #load the shared object file
 adder = CDLL('./adder.so')
 #Find sum of integers
 res_int = adder.add_int(4,5)
 a = c_float(5.5)
 b = c_float(4.1)
 add_float = adder.add_float
 add_float.restype = c_float
 add_float(a, b)
- ctypes接口允许在调⽤C函数时使⽤Python中默认的字符串型和整型,对于其他布尔型和浮点型,应先转化为c_float 
- 不能在C中对对象进⾏操作 
 
Python/C API
- 以特定的⽅式来编写C代码 
- 所有的Python对象都被表⽰为PyObject的结构体,且Python.h头⽂件中提供操作函数 
- 示例 - C代码 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 static PyObject* addList_add(PyObject* self, PyObject* args){
 PyObject * listObj;
 
 //The input arguments come as a tuple, we parse the args to get the various variables
 //In this case it's only one list variable, which will now be referenced by listObj
 if (! PyArg_ParseTuple( args, "O", &listObj ))
 return NULL;
 
 //length of the list long
 length = PyList_Size(listObj);
 
 //iterate over all the elements
 int i, sum =0;
 for (i = 0; i < length; i++) {
 //get an element out of the list - the element is also a python objects
 PyObject* temp = PyList_GetItem(listObj, i);
 //we know that object represents an integer - so convert it into C long
 long elem = PyInt_AsLong(temp);
 sum += elem;
 }
 
 //value returned back to python code - another python object
 //build value here converts the C long to a python integer
 return Py_BuildValue("i", sum);
 }
 //This is the docstring that corresponds to our 'add' function.
 static char addList_docs[] = "add( ): add all elements of the list\n";
 /* This table contains the relavent info mapping -
 <function-name in python module>, <actual-function>,
 <type-of-args the function expects>, <docstring associated with the function>
 */
 static PyMethodDef addList_funcs[] = {
 {"add", (PyCFunction)addList_add, METH_VARARGS, addList_docs},
 {NULL, NULL, 0, NULL}
 };
 /* addList is the module name, and this is the initialization block of the module.
 <desired module name>, <the-info-table>, <module's-docstring>
 */
 PyMODINIT_FUNC initaddList(void){
 Py_InitModule3("addList", addList_funcs, "Add all ze lists");
 } //模块初始化块签名为PyMODINIT_FUNC init{模块名}
- setup.py:编译安装到Python模块 - 1 
 2
 3- from distutils.core import setup, Extension 
 setup(name='addList', version='1.0', \
 ext_modules=[Extension('addList', ['adder.c'])])- 1 - $ python setup.py install 
- 调用 - 1 
 2
 3- import addList 
 l = [1,2,3,4,5]
 print("Sum of List - " + str(l) + " = " + str(addList.add(l)))
 
上下文管理器
- 在有需要的时候,精确地分配和释放资源
- 最⼴泛的案例是with语句
基于类的实现
- ⼀个上下⽂管理器的类,最起码要定义 - __enter__和- __exit__⽅法- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- class File(object): 
 def __init__(self, file_name, method):
 self.file_obj = open(file_name, method)
 def __enter__(self):
 return self.file_obj
 def __exit__(self, type, value, traceback):
 print("Exception has been handled")
 self.file_obj.close()
 return True
 
 with File('demo.txt', 'w') as opened_file:
 opened_file.write('Hola!')
- 过程: - with语句先暂存了File的__exit__
- 调⽤File的__enter__,打开⽂件并返回给with语句
- 使⽤.write()写⽂件
- with语句调⽤之前暂存的__exit__,关闭⽂件
 
- with语句先暂存了File的
异常处理
- 如果发⽣异常,异常的type,value和traceback传递给__exit__处理,如果__exit__返回的是True,这个异常被处理,否则with语句抛出异常
 
        