流畅的python(笔记)
2019-11-08

流畅的python中有很多奇技淫巧,整本书都在强调如何最大限度地利用Python 标准库。介绍了很多python的不常用的数据类型、操作、库等,对于入门python后想要提升对python的认识应该有帮助。目前读一遍记录了一些有共鸣的操作:

Python内置序列类型的主要分类:

按可存放的元素类型分为:容器序列和扁平序列

    容器序列,就是什么都能作为元素往里放,包括另一个序列。需要注意的是,如果元素是序列类型,那么存放的往往是引用,需要小心。常见的容器序列包括:list,tuple,array.array,collections.deque等。扁平序列,存放的都是原子级元素,此时存放的是值而不会是引用。常见的扁平序列包括:str,bytes,bytearray, memoryview, array.array等。

按序列能否被修改分为:可变序列与不可变序列

    可变序列:可以进行增、删、改等操作的序列,包括list, bytearray, array.array, collections.deque, memoryview等。不可变序列:不可进行上述操作的序列,包括tuple, str, bytes等。

字典的变种

标准库里collections模块中提供了很多与字典类型相似的变种。

OrderDict: 这个类型在添加键的时候,会保存顺序,因此键的迭代顺序总是一致的

ChainMap: 该类型可以容纳数个不同的映射对像,在进行键的查找时,这些对象会被当做一个整体逐个查找,直到键被找到为止

Counter: 这个映射类型会给键准备一个整数技术器,每次更行一个键的时候都会增加这个计数器,所以这个类型可以用来给散列表对象计数,或者当成多重集来用。

UserDict: 这个类其实就是把标准的dict用Python又写了一遍。一般用来给程序员想要通过继承dict创建自己的dict时,代替dict使用的。主要是因为直接继承原生dict会出现bug。

defaultdict:处理找不到的键的一个选择当某个键不在映射里, 我们也希望也能得到一个默认值. 这就是 defaultdict , 它是 dict 的子类, 并实现了 missing 方法.

dict的实现以及导致的结果

键必须是可散列的:一个可散列的对象必须满足以下要求。 (1) 支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的。 (2) 支持通过 __eq__() 方法来检测相等性。 (3) 若 a == b 为真,则 hash(a) == hash(b) 也为真。 所有由用户自定义的对象默认都是可散列的,因为它们的散列值由 id() 来获取,而 且它们都是不相等的。字典在内存上开销很大(用内存换效率)。 元组取代字典就能节省空间的原因有两个: (1) 避免了散列表所耗费的空间, (2) 无需把记录中字段的名字在每个元素里都存一遍。键的查询很快键的次序取决于添加顺序往字典里添加新键可能会改变已有键的顺序

set的实现以及导致的结果

结合的元素必须是可散列的集合和消耗内存可以很高效的判断元素是否存在于某个集合元素的次序取决于被添加到集合里的顺序往集合里添加元素,可能会改变集合里已有的元素次序

collections.namedtuple 可以用来构建一个带字段名的元组和一个有名字的类

创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。

>>> from collections import namedtuple>>> City = namedtuple("City", "name country population coordinates")>>> tokyo = City("Tokyo", "JP", 36.933, (35.689722, 139.691667)) >>> tokyoCity(name="Tokyo", country="JP", population=36.933, coordinates=(35.689722,139.691667))>>> tokyo.population 36.933>>> tokyo.coordinates(35.689722, 139.691667)>>> tokyo[1]"JP">>> City = namedtuple("City_Name", "name country population coordinates")>>> tokyo = City("Tokyo", "JP", 36.933, (35.689722, 139.691667))>>> tokyoCity_Name(name="Tokyo", country="JP", population=36.933, coordinates=(35.689722, 139.691667))

当列表不是首选时

    如果我们需要一个只包含数字的列表,那么 array.array 比 list 更高效。数组支持所有跟可变序列有关的操作,包括 .pop、.insert 和 .extend。另外,数组还提供从文件读取和存入文件的更快的方法,如 .frombytes 和 .tofile。set 专为检查元素是否存在做过优化memoryview 是一个内置类,它能让用户在不复制内容的情况下操作同一个数组的不同切片。使用NumPy和SciPy提供的高阶数组和矩阵操作使用双向队列和其他形式的队列(collections.deque 双向队列类、queue类中的 Queue、LifoQueue和PriorityQueue、multiprocessing. Queue、heapq可以把可变序列当作堆队列或者优先队列来使用)

Python 格式化输出

在进行格式化输出时,%r 与 %s 的区别就好比 repr() 函数处理对象与 str() 函数处理对象的差别。

%s -> str(),比较智能;%r -> repr(),处理较为简单和直接; 处理一些简单对象时,二者几乎没有差别.

本文重点列举一些二者的差异化用法:

    处理字符串时

>> s = "world">> print("hello %s"%s)hello world>> print("hello %r"%s)hello "world">> str(s)"world">> repr(s)""world""2. datetime 库中的 datetime 对象>> from datetime import datetime >> timeinfo = datetime.today()>> timeinfodatetime.datetime(2016, 6, 7, 21, 17, 34, 925488)>> type(timeinfo)datetime.datetime>> repr(timeinfo)"datetime.datetime(2016, 6, 7, 21, 17, 34, 925488)">> str(timeinfo)"2016-06-07 21:17:34.925488"

反汇编函数 python opcode

Python dis 模块支持对Python代码进行反汇编, 生成字节码指令。

In[1]: def test():... x = 1... if x < 3:... return "yes"... else:... return "no"In[2]: dis.dis(test) 2 0 LOAD_CONST 1 (1) 3 STORE_FAST 0 (x) 3 6 LOAD_FAST 0 (x) 9 LOAD_CONST 2 (3) 12 COMPARE_OP 0 (<) 15 POP_JUMP_IF_FALSE 22 4 18 LOAD_CONST 3 ("yes") 21 RETURN_VALUE 6 >> 22 LOAD_CONST 4 ("no") 25 RETURN_VALUE 26 LOAD_CONST 0 (None) 29 RETURN_VALUE >>> def add(a, b = 0):... return a + b... >>> >>> dis.dis(add) 2 0 LOAD_FAST 0 (a) 2 LOAD_FAST 1 (b) 4 BINARY_ADD 6 RETURN_VALUE>>>

class memoryview(obj)是python的内置类,如果要用memoryview 去引用一个object, 那么这个object 必须支持buffer protocol, python3 中原生(built-in) 支持buffer protocol的obj有bytes和bytearray,memoryview可以使用不同的方式读取和操作同一块内存,并且原有的内存字节不会随意移动。类似于C中的强转,好处是不会有内存拷贝。

例如,使用memoryview修改一个短整型有符号整数数组的数据。

from array import arrayfrom random import randomnumbers = array("h", [-2, -1, 0, 1, 2]) #signed shortmemv = memoryview(numbers) #5个短整型有符号整数的数组创建一个memoryviewprint (len(memv)) #打印长度print (memv.tolist()) #转换成列表形式memv_oct = memv.cast("B") #内存共享 转换成无符号字符类型print (memv_oct.tolist())memv_oct[5] = 4 #把位置5的字节赋值成4print (numbers) #因为我们把占 2 个字节的整数的高位字节改成了 4,所以这个有符号整数的值就变成了 1024输出如下:5 #数组长度[-2, -1, 0, 1, 2] #列表形式显示[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]#长度扩大一倍 转换为无符号字符类型array("h", [-2, -1, 1024, 1, 2]) #原来的数组被修改

bytearray是可变(mutable)的字节序列,相对于Python2中的str,但str是不可变(immutable)的。在Python3中由于str默认是unicode编码,所以只有通过bytearray才能按字节访问。下面两种行为的对比:简单点就是,str和bytearray的切片操作会产生新的切片str和bytearry并拷贝数据,使用memoryview之后不会。

python2中的例子

不使用memoryview

a = "aaaaaa"b = a[:2] # 会产生新的字符串

a = bytearray("aaaaaa")b = a[:2] # 会产生新的bytearrayb[:2] = "bb" # 对b的改动不影响aabytearray(b"aaaaaa")bbytearray(b"bb")

使用memoryview

a = "aaaaaa"ma = memoryview(a)ma.readonly # 只读的memoryviewTruemb = ma[:2] # 不会产生新的字符串

a = bytearray("aaaaaa")ma = memoryview(a)ma.readonly # 可写的memoryviewFalsemb = ma[:2] # 不会会产生新的bytearraymb[:2] = "bb" # 对mb的改动就是对ma的改动mb.tobytes()"bb"ma.tobytes()"bbaaaa"

Python 中有各种各样可调用的类型,因此判断置的 callable() 函数:

>>> abs, str, 13(<built-in function abs>, <class "str">, 13)>>> [callable(obj) for obj in (abs, str, 13)][True, True, False]

random.shuffle 打乱序列

>>> import random>>> a=range(10)>>> random.shuffle(a)>>> a[1, 0, 8, 5, 6, 7, 9, 3, 2, 4]>>> random.shuffle(a)>>> a[7, 5, 6, 2, 1, 8, 9, 0, 3, 4]

vim常用快捷

0 → 数字零,到行头$ → 到本行行尾a → 在光标后插入o → 在当前行后插入一个新行O → 在当前行前插入一个新行cw → 替换从光标所在位置后到一个单词结尾的字符. → (小数点) 可以重复上一次的命令NG → 到第 N 行 (注意命令中的G是大写的,另我一般使用 : N 到第N行,如 :137 到第137行)gg → 到第一行。(相当于1G,或 :1)G → 到最后一行。在 Insert 模式下,你可以输入一个词的开头,然后按或是,自动补齐功能就出现了…

内置函数

MathFunction Descriptionabs() Returns absolute value of a numberdivmod() Returns quotient and remainder of integer divisionmax() Returns the largest of the given arguments or items in an iterablemin() Returns the smallest of the given arguments or items in an iterablepow() Raises a number to a powerround() Rounds a floating-point valuesum() Sums the items of an iterableType ConversionFunction Descriptionascii() Returns a string containing a printable representation of an objectbin() Converts an integer to a binary stringbool() Converts an argument to a Boolean valuechr() Returns string representation of character given by integer argumentcomplex() Returns a complex number constructed from argumentsfloat() Returns a floating-point object constructed from a number or stringhex() Converts an integer to a hexadecimal stringint() Returns an integer object constructed from a number or stringoct() Converts an integer to an octal stringord() Returns integer representation of a characterrepr() Returns a string containing a printable representation of an objectstr() Returns a string version of an objecttype() Returns the type of an object or creates a new type objectIterables and IteratorsFunction Descriptionall() Returns True if all elements of an iterable are trueany() Returns True if any elements of an iterable are trueenumerate() Returns a list of tuples containing indices and values from an iterablefilter() Filters elements from an iterableiter() Returns an iterator objectlen() Returns the length of an objectmap() Applies a function to every item of an iterablenext() Retrieves the next item from an iteratorrange() Generates a range of integer valuesreversed() Returns a reverse iteratorslice() Returns a slice objectsorted() Returns a sorted list from an iterablezip() Creates an iterator that aggregates elements from iterablesComposite Data TypeFunction Descriptionbytearray() Creates and returns an object of the bytearray classbytes() Creates and returns a bytes object (similar to bytearray, but immutable)dict() Creates a dict objectfrozenset() Creates a frozenset objectlist() Constructs a list objectobject() Returns a new featureless objectset() Creates a set objecttuple() Creates a tuple objectClasses, Attributes, and InheritanceFunction Descriptionclassmethod() Returns a class method for a functiondelattr() Deletes an attribute from an objectgetattr() Returns the value of a named attribute of an objecthasattr() Returns True if an object has a given attributeisinstance() Determines whether an object is an instance of a given classissubclass() Determines whether a class is a subclass of a given classproperty() Returns a property value of a classsetattr() Sets the value of a named attribute of an objectsuper() Returns a proxy object that delegates method calls to a parent or sibling classInput/OutputFunction Descriptionformat() Converts a value to a formatted representationinput() Reads input from the consoleopen() Opens a file and returns a file objectprint() Prints to a text stream or the consoleVariables, References, and ScopeFunction Descriptiondir() Returns a list of names in current local scope or a list of object attributesglobals() Returns a dictionary representing the current global symbol tableid() Returns the identity of an objectlocals() Updates and returns a dictionary representing current local symbol tablevars() Returns __dict__ attribute for a module, class, or objectMiscellaneousFunction Descriptioncallable() Returns True if object appears callablecompile() Compiles source into a code or AST objecteval() Evaluates a Python expressionexec() Implements dynamic execution of Python codehash() Returns the hash value of an objecthelp() Invokes the built-in help systemmemoryview() Returns a memory view objectstaticmethod() Returns a static method for a function__import__() Invoked by the import statement

跟运算符无关的特殊方法

类别 方法名字符串 / 字节序列表示形式 __repr__、__str__、__format__、__bytes__数值转换 __abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__集合模拟 __len__、__getitem__、__setitem__、__delitem__、__contains__迭代枚举 __iter__、__reversed__、__next__可调用模拟 __call__上下文管理 __enter__、__exit__实例创建和销毁 __new__、__init__、__del__属性管理 __getattr__、__getattribute__、__setattr__、__delattr__、__dir__属性描述符 __get__、__set__、__delete__跟类相关的服务 __prepare__、__instancecheck__、__subclasscheck__

Bisect模块管理有序的序列

bisect.bisect_left(a,x, lo=0, hi=len(a)) :查找在有序列表 a 中插入 x 的index。lo 和 hi 用于指定列表的区间,默认是使用整个列表。如果 x 已经存在,在其左边插入。返回值为 index。bisect.bisect_right(a,x, lo=0, hi=len(a))bisect.bisect(a, x,lo=0, hi=len(a)) :这2个函数和 bisect_left 类似,但如果 x 已经存在,在其右边插入。bisect.insort_left(a,x, lo=0, hi=len(a)) :在有序列表 a 中插入 x。和 a.insert(bisect.bisect_left(a,x, lo, hi), x) 的效果相同。bisect.insort_right(a,x, lo=0, hi=len(a))bisect.insort(a, x,lo=0, hi=len(a)) :和 insort_left 类似,但如果 x 已经存在,在其右边插入。Bisect 模块提供的函数可以分两类: bisect* 只用于查找 index, 不进行实际的插入;而 insort* 则用于实际插入。

当list不是最优选择时,dict是python的核心类型,但它是以空间换时间的结果,比较占内存,tuple是dict结构比较好的替代,set用来做是否包含和去重很合适。

from array import array from random import randomfloats = array("d", (random() for i in range(10**7))) fp = open("floats.bin", "wb")floats.tofile(fp) fp.close()floats2 = array("d") fp = open("floats.bin", "rb")floats2.fromfile(fp, 10**7) fp.close()floats2 == floats

Python_内置四种队列

from queue import Queue #LILO队列q = Queue() #创建队列对象q.put(0) #在队列尾部插入元素q.put(1)q.put(2)print("LILO队列",q.queue) #查看队列中的所有元素print(q.get()) #返回并删除队列头部元素print(q.queue)from queue import LifoQueue #LIFO队列lifoQueue = LifoQueue()lifoQueue.put(1)lifoQueue.put(2)lifoQueue.put(3)print("LIFO队列",lifoQueue.queue)lifoQueue.get() #返回并删除队列尾部元素lifoQueue.get()print(lifoQueue.queue)from queue import PriorityQueue #优先队列priorityQueue = PriorityQueue() #创建优先队列对象priorityQueue.put(3) #插入元素priorityQueue.put(78) #插入元素priorityQueue.put(100) #插入元素print(priorityQueue.queue) #查看优先级队列中的所有元素priorityQueue.put(1) #插入元素priorityQueue.put(2) #插入元素print("优先级队列:",priorityQueue.queue) #查看优先级队列中的所有元素priorityQueue.get() #返回并删除优先级最低的元素print("删除后剩余元素",priorityQueue.queue)priorityQueue.get() #返回并删除优先级最低的元素print("删除后剩余元素",priorityQueue.queue) #删除后剩余元素priorityQueue.get() #返回并删除优先级最低的元素print("删除后剩余元素",priorityQueue.queue) #删除后剩余元素priorityQueue.get() #返回并删除优先级最低的元素print("删除后剩余元素",priorityQueue.queue) #删除后剩余元素priorityQueue.get() #返回并删除优先级最低的元素print("全部被删除后:",priorityQueue.queue) #查看优先级队列中的所有元素from collections import deque #双端队列dequeQueue = deque(["Eric","John","Smith"])print(dequeQueue)dequeQueue.append("Tom") #在右侧插入新元素dequeQueue.appendleft("Terry") #在左侧插入新元素print(dequeQueue)dequeQueue.rotate(2) #循环右移2次print("循环右移2次后的队列",dequeQueue)dequeQueue.popleft() #返回并删除队列最左端元素print("删除最左端元素后的队列:",dequeQueue)dequeQueue.pop() #返回并删除队列最右端元素print("删除最右端元素后的队列:",dequeQueue)以上队列在多线程中可以使用的且线程安全,但在多进程中都不能用于通信。在多进程中,需要这样使用:from multiprocessing import Process, Queuemyqueue = Queue(100)## 参考https://blog.csdn.net/sinat_38682860/article/details/80392493 https://www.cnblogs.com/cmnz/p/6936181.html

关键字

from keyword import kwlistprint(kwlist)

builtins模块

import builtinsdir(builtins)