Effective Python笔记

第一章:用Pythonic方式来思考

第2条 PEP8

《Python Enhancement Proposal #8》8号Python增强提案。

空白:①4个空格代表tab ②每行<=79字符 ③分行后加4个空格 ④类中方法空1行,方法和类空2行

命名:①函数、变量、属性用小写字母和下划线组成 ②受保护用单下划线,私有用双下划线 ③类与异常用驼峰 ④模块级别常量用全大写 ⑤类中实例方法首个参数是self,表示改对象;类方法的首个参数是cls,表示该类。

表达式和语句:①not不要放在表达式前面 ② 采用if not list 判断列表是否为空③import放开头且使用绝对路劲引用(但可以form . import models)④import顺序按照标准库、第三方模块库、自用模块导入,每部分按字母顺序排列。

第3条:了解bytes、str、unicode区别

isinstance(obj, class)判断class类型是否是obj的(父)类

str.encode(‘utf-8’)转变为bytes类型 bytes.decode(‘utf-8’)转变为str类型

在读写文件中,默认是’utf-8’,如果使用二进制必须加上‘b’

python3 bytes是8位值的序列,str是包含Unicode字符序列。

python2 str是8位值的序列,unicode是包含Unicode字符序列。若str只包含7位ASCII,可以使用相关操作同时使用。

第4条:用辅助函数来取代复杂的表达式

repr(obj),将obj对象转换成字符串类型

or左边表达式为真则用左边的,否则用右边的 a = False or ‘1’ # a=1

if/else表达式 a = x if x>y else y

第5条:了解切割序列的办法

assert 表达式, 当表达式等于False时,抛出AssertionError

start或end索引越界也不会出问题

第6条:在单次切片操作内,不要同时指定start、end和stride

同时指定start、end和stride会导致代码难以阅读,stride尽量使用正值。

可考虑使用itertools模块中的islice。(第46条:使用内置算法与数据结构:)

第9条:用生成器表达式来改写数据量较大的列表推导

it = (x for x in range(20000))
next(it)

两个生成器可以串起来用,产生连锁反应。

第13条:合理利用try/except/else/finally

else后面的代码是在try顺利完成后才运行。

except用法

    except ZeroDivisionError as e:
        raise ValueError('dsa') from e

第二章:函数

第15条:了解如何在闭包里使用外围作用域中的变量

用nonlocal语句

nonlocal与global相互补充,nonlocal修改闭包外那个作用域变量,global修改模块作用域的变量

也可以用列表、字典、集合来取代,这样作用域会自动向外搜索

第16条:考虑生成器来改写直接返回列表的函数

多用生成器,可转list。生成器⊆迭代器

第17条:在参数上面迭代时,要多加小心

注意生成器只能遍历一次!如果重复迭代,第二次不会报错,会产生一个空列表。解决办法:直接传入迭代器函数进去。

迭代器其实就是fun.__ iter __这个特殊方法

第18条:用数量可变的位置参数减少视觉杂讯

*arg 可变长,转变为元组

**kwargs 字典

也可用默认值代替*arg

第20条:用None和文档字符串来描述具有动态默认值的参数

参数中有默认值,函数被反复调用,默认值只会产生一次。解决办法用None

def gen(bad={}):
    return bad
def main():
    f1 = gen()
    f1['1'] = 1
    f2 = gen()
    f2['2'] = 3
    print(f1)  # {'1': 1, '2': 3}
    print(f2)  # {'1': 1, '2': 3}

第三章:类与继承

第22条:尽量用辅助类来维护程序的状态,而不是用字典和元组

namedtuple

Grade = collections.namedtuple('Grade', ('score', 'weight'))
a = Grade(100, 0.2)  # Grade(score=100, weight=0.2) 可迭代 a.score

如果类太复杂,可以拆成多个类。如:Gradebook->Student->Subject

第23条:简单接口应该接受函数,而不是类的实例

字典初始化定义

res = collections.defaultdict(fun, dict)
# fun函数返回的是字典初始化值

assert 条件,如果条件为false,则程序报错

第24条:以@classmethod形式的多态去通用地构建对象

  • 多态:多种状态,接口的多种不同实现方式。写出通用代码。

  • 定义公共基类、继承

class InputData:
    def read(self):
        raise NotImplementedError


class PathInputData(InputData):
    def __init__(self, path):
        super().__init__()
        self.path = path

    def read(self):
        print(self.path)
        return 0
  • @classmethod是类的方法,第一个参数是cls。每个类只有一个__ init__方法,所以需要@classmethod来实现抽象类的方法。

第25条:用super初始化父类

  • 出现砖石型的继承关系时候,使用super会同时初始化两个类。

第26条:只在使用Mix-in组件制作工具类时进行多重继承

  • 尽量避开多重继承

  • 若一定使用,则用mix-in类。(额~其实这里我想不出有什么用)

第27条:多用public属性,少用private属性

  • protect属性是单下划线,private是双下划线。

  • @property将protect属性写成函数访问

  • 如果要访问私有属性,则继承A类,然后obj._A__private可访问,因为python会对私有属性的名称做变换

  • 多用protect属性,少用private,当子类不受控制时,才考虑用private

第28条:继承collection.abc以实现自定义的容器 类型

  • collection.abc中有大量抽象类,如果没有实现基类的功能会报错

第四章:元类及属性

  • 元类:class语句就是元类,每次定义具体类时,都提供独特的行为。

第29条:用纯属性取代get和set方法

  • @property返回属性;@attr.setter设置属性
  • hasattr(class, ‘attr’)判断父类有无该属性

第30条:考虑用@property来代替属性重构

  • repr给程序员看的,str给使用者看的,避免输出误以为是报错。repr>str

第31条:用描述符来改写需要复用的@property

  • @property修饰器不能复用
  • classmethod第一个参数是cls,可以调用自身类,而staticmethod不可以调用自身类

第32条:用_ getattr_ 、_ getattribute_ 和_ setattr _实现按需生成的属性

  • getattr当对象找不到对应属性时,会在这里找

  • def __getattr__(self, item):
        value = '123'
        setattr(self, item, value)  # 设置这个值
        return value
    
  • getattribute无论属性是否在__ dict__中,都会触发该函数,如果没有该属性会raise AttributeError.调用该方法一定要super(),否则会递归的一直调用。

33-35书上的内容过旧

第33条:用元类来验证子类

  • new和init区别:new是创建类前运行的,init是初始化对象的属性
  • metaclass用来验证子类

第五章:并发及并行

第六章:内置模块

第46条:使用内置算法与数据结构

第46条:使用内置算法与数据结构

第七章:协作开发

第八章:部署

你可能感兴趣的:(Python)