Python高级拾遗1

1、Python解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以两个下划线开头,以两个下划线结尾,这些特殊方法名能让你自己的对象实现和支持以下语言架构并与之交互:迭代、集合类、属性访问、运算符重载、函数和方法的调用、对象的创建和销毁、字符串表示形式和格式化、管理上下文(with块)。

namedtuple具名元组,创建一些有少数属性没有方法的类。具名元组有一些自己的专有属性:_fields属性、类方法_make(iterable)和实例方法_asdict()。

__getitem__:提供索引、切片、迭代(和反向迭代)。

import collections
from random import choice

Card = collections.namedtuple('Card',['rank','suit'])#Card is class

class FrenchDeck:
    ranks = [str(n) for n in range(2,11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()

    def __init__(self):
        self._cards = [Card(rank,suit) for suit in self.suits
                       for rank in self.ranks]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self,position):
        return self._cards[position]

suit_values = dict(spades=3,hearts=2,diamonds=1,clubs=0)
def spades_high(card):
    rank_value = FrenchDeck.ranks.index(card.rank)
    return rank_value * len(suit_values) + suit_values[card.suit]

deck = FrenchDeck()
'''for card in reversed(deck):
    print(card)'''

for card in sorted(deck,key=spades_high):
    print(card)

特殊方法的存在是被解释器调用的,并不是被自己调用的,如__len__方法,用户实际调用的是len,内部会调用__len__。

很多时候,特殊方法的调用是隐式的,比如for i in x:,背后调用的实际是iter(x),这个函数背后实际上是__iter__(x)。

Python语言参考手册中的Data Model列出了83个特殊方法的名字,其中47个用于实现算术运算、位运算和比较操作。

2、序列

list、tuple、collections.deque这些序列能存放不同的类型,称为容器序列;str、bytes、bytearray、memoryview和array.array只能放同一种类型,称为扁平序列。容器序列存放的是它们所包含的任意对象的引用,扁平序列存放的是值。

可变序列:list、bytearray、array.array、collections.deque和memoryview

不可变序列:tuple、str和bytes

列表推倒的作用只有一个:生成列表。

元组拆包:city,year,pop=('Tokyo',2003,32450)    可以用_作占位符,用*接受多参数。

除了跟增减元素相关的方法之外,元组支持列表的其他所有方法,元组没有__reversed__方法。

如果赋值的对象是切片,那么赋值语句的右边必须是可迭代对象。

嵌套的列表易出错的地方:[['-']*3]*3,实际上里面的每一个嵌套列表是同样的引用对象,正确的写法为:[['-']*3 for i in range(3)]

序列的增量赋值:+=背后的特殊方法是__iadd__(就地加法),如果一个类没有实现这个方法的话Python就会退一步调用__add__,可变序列一般都实现了__iadd__方法。str是一个例外,因为对字符串做+=太普遍了,所以CPython对它做了优化,分配初始化内存的时候会为它留出额外的可扩展空间。

不要把可变对象放在元组里面,增量赋值 不是一个原子操作,可以用dis.dis得出汇编代码,分析性能优化。

list.sort会就地排序列表,返回None;内置sorted会新建一个列表作为返回值,这个方法可接受任何形式的可迭代对象作为参数,最后返回一个列表。sorted(sequencexxx,key,reverse)

bisect模块包含两个主要函数,bisect和insort,两个函数都利用二分查找法在有序序列中查找或插入元素。

array.array:如果需要只包含数字的列表,array.array比list更高效,还提供存取文件的方法:frombytes和tofile。

memoryview(内存视图)是一个内置类,能让用户在不复制内容的情况下共享内存,数据结构可以是任何形式,如PIL图片、SQLite数据库。

Numpy、Scipy、Pandas、Blaze

collections.deque是一个线程安全、可以快速从两端添加或删除元素的数据类型。

3、泛映射类型

标准库里所有映射类型都是用dict实现的,它的键必须是可散列的。如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,而且这个对象需要实现__hash__方法。原子不可变序列str、bytes和数值类型都是可散列类型,frozenset也是可散列的,元组的话当他所包含的对象都是可散列的时候它才是可散列的。

一般来说,用户自定义类型都是可散列的,散列值就是它们的id()函数返回值。

字典的几种构造方法:

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),('onw',1),('three',3)])            e = dict({'three':3,'one':1,'two':2})             a=b=c=d=e

字典推导法

dict、collections.defaultdict、collections.OrderedDict

映射的弹性键查询:一个是通过defaultdict这个类型,一个是通过重写dict的__missing__方法。在defaultdict中如果查询不到键,default_factory会被调用。

如果要自定义一个映射类型,从collections.UserDict类继承比较好,这个类是把标准的dict用python又实现了一遍。

collections.OrderedDict在添加键的时候会保持顺序;collections.ChainMap可以容纳数个不同的映射对象;collections.Counter会给键准备一个整数计数器;

types模块的MappingProxyType会返回一个映射的只读视图。

集合中的元素必须是可散列的,set本身是不可散列的,frozenset是可散列的。

空集合必须用set创建而不是{}。

字典使用了散列表,散列表又必须是稀疏的,这导致它的空间效率低下,典型的空间换时间。

往字典里添加新键的时候Python解释器可能会为它扩容,这个过程中可能会发生新的散列冲突,导致新散列表中键的次序发生变化。如果你在迭代一个字典的所有键的过程中同时对字典进行修改,那么这个循环可能会跳过一些键。

4、bytes和bytearray的各个元素介于0-255之间,bytearray没有字面量句法,二进制序列有个类方法是str没有的:fromhex。

构建bytes或bytearray实例可调用各自的构造方法,传入以下参数:一个str对象和一个encoding关键字参数;一个可迭代对象,提供0-255之间的值;一个整数,使用空字节创建对应长度的二进制序列;一个实现了缓冲协议的对象。

struct模块提供了一些函数,把打包的字节序列转换成不同类型字段组成的元组,还有一些函数用于执行反向转换。struct模块能处理bytes、bytearray和memoryview。

为UnicodeEncodeError和UnicodeDecodeError指定错误处理函数。

统一字符编码探测包:chardet。

BOM:byte-order-mark,UTF-16中有,指明字节序。UTF-8的优势是,不管设备使用哪种字节序,生成的字节序列始终一致,因此不需要BOM。

Unicode三明治:bytes—>str     处理str      str—>bytes

不能依赖系统的默认编码。  

unicode标准提供了一个完整的数据库。

5、函数

高阶函数:接受函数为参数或者把函数作为结果返回的函数是高阶函数。比较常见的高阶函数有map、filter、deduce。列表推导和生成器表达式能代替map和filter的功能。

sum和deduce的通用思想是把某个操作连续应用到序列的元素上,累计之前的结果,把一系列值归约成一个值。

Python句法限制了lambda函数的定义体只能使用纯表达式,不能赋值,也不能使用while、try等python语句。在高阶函数的参数列表中最适合使用lambda表达式。

callable函数判断对象是否可调用。函数注解,注解只是元数据,可以供IDE、框架和装饰器等工具使用。

猜你喜欢

转载自blog.csdn.net/chenkaifang/article/details/81505186