zoukankan      html  css  js  c++  java
  • 流畅的python笔记

    鸭子类型协议不完全总结
    序列:len,getitem
    切片:getitem
    v[0]分量的取值和写值:getitem和setitem
    v.x属性的取值和写值:getattr和setattr
    迭代:1)iter,2)getitem
    上下文管理器:enter,exit
    +=:1)iadd,2)add
    可散列:hash,eq
    in测试:1)contains,2)iter,3)getitem

    第一章,python数据模型
    __repr__得到对象的字符串表现形式
    if obj,实际执行的是bool(obj),python解释器调用obj.__bool__,如果没有__bool__,会调用__len__看是否为0
    len(obj),python解释器调用obj.__len__()
    obj[key],python解释器调用obj.__getitem__(key)
    'hello world %s' % x, 'hello world %r' % x ,对于x=123两者输出都一样,x='abc'前者输出hello world abc,后者输出hellow world 'abc' 

    第二章,序列构成的数组
    容器序列:引用,list、tuple、collections.deque
    扁平序列:值,str、bytes、array.array
    可变序列:list、array.array
    不可变序列:tuple、str
    *args :序列中的值
    args:序列
    列表推导不再会有变量泄漏的问题
    元组拆包:_,a, b, *args = [1, 2, 3, 4, 5, 6],不要的可以用_或者*args
    切片实际操作步骤:首先生成切片对象slice(a, b, c),再使用__getitem__方法取值
    序列使用 + 和 * 时,原序列都不会被修改,而是新建序列
    创建3个空列表:应该使用[[] for i in range(3)],而不是使用[[]] * 3
    array.array:浮点数效率高
    set:in测试效率高

    第三章,字典和集合
    用户自定义类型的对象都是可散列的,散列值就是id()返回的值
    dict.get(k, w):查找key时,设置默认
    dict.setdefault(k, w):更新key时,设置默认
    defaultdict(type):可以设置字典value的缺省类型,例如list
    __missing__:找不到key时会调用__missing__特殊方法
    集合没有getitem,但是有iter

    第四章,文本和字节序列
    待补充

    第五章,一等函数
    函数本质上就是定义了__call__的类,此外还有些函数特有的属性,例如__kwdefaults__,__defaults__,__get__等等
    建议用生成器表达式取代map,filter
    匿名函数lambda,主要适用于传参,可以省略函数名
    operator:提供了一些算数运算符函数,例如相乘mul
    functools.partial(func, arg):用于冻结参数,func是可调用对象,arg是冻结的参数

    第六章,使用一等函数实现设计模式
    用类实现策略模式:用类实现具体策略,相同部分作为基类,不同部分作为子类
    用函数实现策略模式:用函数实现具体的策略,函数作为参数传递给类的实例

    第七章,函数装饰器和闭包
    自由变量:未在本地作用域中绑定的变量,可以被内部嵌套函数访问,并能保留下来的
    nonlocal:声明变量为自由变量
    基本装饰器(2层嵌套):必须return2次,如果只return wrapper,则被装饰函数有返回值时会永远返回None
    参数化装饰器(3层嵌套):支持装饰器传参

    基本装饰器代码实现:

    def clock(fn):
        @functools.wraps()
        def wrapper(*arg, **kwargs):
            ret = fn(*arg, **kwargs)
            return ret
        return wrapper    

    第八章,对象引用、可变性和垃圾回收
    变量是标注,不是盒子:引用式变量(例如列表、字典)可以同时有多个不同的变量名
    引用性变量的不同变量名,值/id都是相等的
    python的'==':只判断值是否相等,id可以不等。有点类似js的'==='
    可以用is判断id是否相同,不必使用id()函数
    元组的不可变性:保存的引用不可变,但是引用的对象可以变
    创建别名:b = lista
    浅复制:b = lista[:],b = lista.copy(),b= copy.copy(lista)
    深复制:b= copy.deepcopy(lista)
    如果lista列表内部有“可变的引用对象”(例如字典、集合、列表,元组算不可变的引用对象),发生改变时,会影响到浅拷贝,但不会影响到深拷贝。
    防御可变参数:函数传参时,可变参数的默认值必须使用None。如果使用可变参数作为默认值,则不传参时,多个函数调用方会共享同一个可变参数。
    python是按引用传参的,对参数修改后:1)不可变参数会重新开辟内存,实质相当于传统的按值传参;2)可变参数会就地修改,实质相当于传统的按引用传参。

    第九章,符合python风格的对象
    尽早捕获错误:如果涉及到参数转换,在__init__中完成可以尽早捕获错误
    classmethod:静态函数,第一个参数是类,可以调用类属性/类方法
    staticmethod:静态函数,没有特殊参数,本质上就是放在类中的全局函数
    格式化:format
    私有属性:__x可以通过“object_classname__x”来访问,所以本质上单下划线和双下划线没什么区别
    属性设置为只读:私有属性 + @property
    __slots__属性:节省空间,使用后无法新增属性

    第十章,序列的修改、散片和切片
    获取类的引用方法:type(self),self.__class__,被@classmethod装饰的函数的第一个参数。要访问类变量,必须先获取类的引用。
    实现了一个多维向量类(序列):
      v1:兼容2d,一些基本的序列方法
      v2:实现getitem,支持分量访问、切片访问。没有实现setitem,所以不支持分量设值、切片设值。
      v3:实现getattr和setattr,支持属性访问,setattr必须同时实现,否则对属性进行设值后(v.x)会与分量值(v[0])产生冲突
      v4:实现eq和hash,可散列
      v5:格式化

    第十一章,从协议到抽象基类
    鸭子类型:协议是非正式的接口
    白鹅类型:使用抽象基类正式明确接口
    abc:自定义抽象基类,抽象方法
    collections.abc:提供一些内置的抽象基类
    numbers:抽象基类数字塔。包括Number,Complex,Real,Rational,Intergral。
    抽象基类(abc.ABC):抽象基类必须继承abc.ABC,才能约束子类必须实现抽象方法,抽象基类不能被实例化
    抽象方法(@abc.abstractmethod):抽象基类的抽象方法,不用实现,子类继承抽象基类时必须实现抽象方法,才能被实例化
    抽象基类主要作用:作为超类;isinstance检查;注册(xx.register);自动识别(不用注册或继承也能通过isinstance检查)
    isinstance检查举例:collections.abc.Sequence抽象基类包含的方法有__contains__,__iter__,__len__,__getitem__,__reversed__,index,count,其中抽象方法是__len__,__getitem__。如果某对象想通过isinstance(obj, collections.abc.Sequence)检查,方法一是继承Sequence并实现2个抽象方法,方法二是自己实现所有的方法,并注册Sequence.register。
    猴子补丁:直接给类(注意不是类的实例)添加新的方法。这样可以在运行时修改类或模块,而不改动源码。
    python是动态强类型语言:动态指运行时检查类型,强类型指很少隐式转换类型。

    第十二章,继承的优缺点
    内置类型字典更新值的方法:
    DoppeDict(one=1):调用__init__()
    DoppeDict['two'] = 2:设置时调用__setitem__(),获取时调用__getitem__()
    DoppeDict.update('three', 3):调用update(),
    子类化内置类型时,不会调用用户定义的类覆盖的特殊方法
    多重继承:广度优先,深度优先,python3是广度优先
    委托给父类执行:super().func(),多重继承时可以指定由哪个父类执行xx.func()
    继承UserDict, UserList, UseString:速度慢,以扩展
    继承Dict, List, String:速度快,难扩展

    第十三章,正确重载运算符
    一元: -neg,+pos,~invert
    算术: +add,
    比较: ==eq,!=ne
    增量赋值: +=iadd
    运算时,先正向,后反向,比较运算还会比较id,通过返回NotImplemented切换
    python3.5新引入@做点积运算

    第十四章,可迭代的对象、迭代器和生成器
    iterable具有可调用的iterator,可以通过iter(iterable)从iterable中获得iterator。
    iterator的实现方法:1)iter + next,其中iter方法中return self,next方法中逐个返回值。2)iter,iter方法中使用yield生成器返回值。
    generator属于iterator。
    Sequence实现了getitem和len特殊方法就可以被迭代,因为解释器在尝试迭代对象x时,会执行如下步骤:1)调用iter(x);2)没有iter就调用getitem;
    StopIteration表示迭代器到头。
    典型的迭代器:2个类,iterable和iterator作为2个类分开实现,iterable中的iter返回iterator;iterator中的iter返回self,next逐个返回值。
    糟糕的迭代器:1个类,同时在iterable中实现了iterator,即iterable中的iter返回self,同时具有next方法逐个返回值。
    生成器:1个类,iterable的iter返回yield生成器。
    惰性生成器:1个类,iterable的iter返回yield生成器,但是生成器的内容是惰性获取,例如获取文本时由finditer替代findall。
    生成器表达式:1个类,iterable的iter返回一个生成器表达式。
    多层for循环时,可以用yield from替代内层for循环

    第十五章,上下文管理器和else块
    用法:with xxx as yyy
    支持同时打开两个对象:with xxx as yyy, aaa as bbb
    上下文管理器协议:__enter__方法中返回yyy(没有提供内容时直接返回None),__exit__方法中做好退出释放资源操作

    第十六章,协程
    进程:有独立内存空间。
    线程:CPU调度最小单位,共享内存。
    协程:用户态的轻量级线程,上下文切换块,CPU感知不到协程,只使用一个线程。
    在其他语言中,协程意义不大,可以通过多线程解决I/O,但是python有GIL多线程也是伪多线程,同一时间只能有一个线程,同步编程I/O阻塞称为瓶颈,可以用协程处理高I/O操作。
    同步编程并发:单纯通过多进程和多进程进行同步编程,切换线程和切换进程有开销,还需要解决进程间/线程间资源交互问题。
    异步编程并发:协程,回调。
    协程: a = yield b,先执行b产出值;再执行a赋值;可以没有a,即只产出不赋值(生成器);可以没有b,即只赋值不产出值(最后一起返回)。
    协程流程:
    1)预激:手动next; 装饰器; yield from;
    2)发送至:send;
    3)关闭:发送哨符值; close(); throw()输入未捕捉的异常
    4)异常处理:throw()输入except捕捉的异常
    5) 获取协程返回值:PEP380定义; yield from;

    第十七章,使用future处理并发
    I/O密集型:多线程threading —> futures.ThreadPoolExecutor
    CPU密集型:多进程multiprocessing —> futures.ProcessExecutor
    python有GIL,同一时间只能允许一个线程执行python字节码,而线程是调度CPU的最小单位,因此多线程无法满足CPU密集型操作。其他语言开启多线程可以调度多个CPU的可以满足CPU密集型操作。
    futures多进程/多线程处理方法:
    map:全部完成后获取结果,再执行后续代码,只能处理相同的函数(函数参数可以不同)
    submit + as_completed:有完成的就先获取结果,可处理不同函数

    第十八章,使用asyncio包处理并发
    asyncio用于异步IO
    python3.5开始引入了新语法async和await:@asyncio.coroutine替换为async def …,yield from替换为await



    第十九章,动态属性和特性
    如果想把属性x变成只读:可以通过@property完成,特性名称需要与init中静态属性名称不同,因为如果相同没有提供setter方法无法完成赋值。
    如果想限制静态属性:可以增加@x.setter装饰同名函数,静态属性名称self.x,@property特性名称x,@x.setter装饰的名称x三者相同,这时setter中的函数可以实现一些限制和验证操作,如果不做这些操作那就可以不用property和setter。



    第二十章,属性描述符
    限制静态属性的方法:
    1)init函数中判断并raise error,缺点是只有实例化时有效,实例化后无法限制对属性进行更改
    2)@property + @xx.setter,缺点是不能重复使用,有多个属性想限制时代码量会非常大
    3)描述符

    第二十一章,元类编程
    待补充

  • 相关阅读:
    code3728 联合权值
    Codevs 4600 [NOI2015]程序自动分析
    code1540 银河英雄传说
    code1074 食物链
    堆排序
    哈夫曼树与哈夫曼码
    优先队列用法
    code1154 能量项链
    code1225 八数码Bfs
    javascript5
  • 原文地址:https://www.cnblogs.com/guxh/p/10224440.html
Copyright © 2011-2022 走看看