前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Effictive python》读书笔记2

《Effictive python》读书笔记2

原创
作者头像
J_J
修改2019-03-14 20:23:06
1.1K0
修改2019-03-14 20:23:06
举报
文章被收录于专栏:每周一脱topic

做下读后的核心观点记录。

二、函数部分

第14条 尽量用异常来表示特殊情况,而不是None等值

因为none值和0等,在判断语句中都类似false,可能跟正常情况冲突。python更推崇抛出异常的方式来处理特殊情况。所以异常情况可以直接抛出自定义的异常,让外面处理,没有异常,都是正常值。

第15条了解如何在闭包里使用外面域的变量

代码里某条表达式中使用了变量,python解释器如何寻找?

  1. 当前函数的作用域;
  2. 2.任何外围作用域;
  3. 3.包含当前代码的模块的作用域(也叫全局作用域, globle scope)
  4. 4.内置作用域(python内置的,包含len、str等函数的作用域)
  5. 找不到变量时抛NameError

给变量赋值,有所不同:

  1. 如果当前作用域有这个变量,那么变量保存新值。
  2. 没有,就会在当前作用域创建新变量。

python3,nonlocal声明变量表示赋值时在上层作用域中查找该变量,不会延伸到全局作用域

python2,没有nolocal。可以用一个[]中的下标,赋值来替代。例如found[0] = True。这样的赋值会向上层去找作用域。

第16条 可以用生成器来改写返回列表的函数

当调用生成器的next函数时,会执行到下一个yield表达式,并将返回yield的值

这样会节省内存,输入量。

第17条 生成器作为参数的时候要注意

生成器是有状态的,只能迭代1次。造成枯竭。

可以写个容器类,实现__iter__()方法(里面要yield返回每次迭代的东西)。这样for去迭代的时候,每次都会生成一个新的iter对象。

第18条 用可变参数,来防止参数过多

可变数量参数(star args)

代码语言:javascript
复制
def myfunc(*args, **kwargs)

变长参数在传给函数时,先全部转化为元组,这时候生成器会占用大量内存,导致问题。因此适用场景要注意,参数数量不能过多。

在变长参数上增加其它的位置参数,可能产生难以排查的bug。

可以使用*来展开list,**展开字典,传给函数。

第19条 用关键字参数来设置可选参数

增加参数时不影响。

第20条 动态的默认参数可以用None和注释来描述

第21条 确保调用者使用关键字参数

Python3

*号后的参数,只能以关键字参数的形式赋值

python2

使用**kwarg,不定参数,字典形式。pop检查,不符合报错

三、 类部分

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

类内部用字典或列表做底层数据结构,嵌套超过2层就要考虑重构了。使用辅助类来简化逻辑。

拆分后,类和代码可能会变多,但可维护性和逻辑简单了。

第23条  简单的接口可以接受函数而不是类

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

类似于静态的new对象的方法。

第25条 用super初始化父类

python2

super(ConcretClass, self).__init__(paras)

python3

super(__class__, self).__init__(paras)

super().__init(paras)

第26条 只在使用Mixin制作工具类时,进行多重继承

作者不推崇使用多重继承。

mix-in是一种小型类,只定义了一套方法,没有定义实例属性,不要求调用__init__

第27条 类中属性多用public,少用private

两个下划线开头为private。

实例不能访问,子类无法访问父类的private属性,类方法可以访问。

内部机制:定义的私有变量编译器会改名,例如:ExampleClass.__p私有属性,编译器会将此私有变量改名为_ExampleClass__p。

所以私有变量在外部也是可以直接访问的,python无法保证private字段的私密性。

为了更便于继承等,不要使用private类型,有隐私要求的可使用protected类型(代码规范,不是强制),一个下划线。并在文档中详细说明。

有个场景可考虑使用private,父类属性名字很常见,子类又不受自己控制,可能引起子类混淆时。

第28条 自定义容器类,可以继承collections.abc来做

因为可能忘记实现一些方法,例如__len__,__getitem__等,所以通过继承collections.abc模块里的抽象类来防止遗忘。

四、 元类及属性

第29条  直接操作属性,而不是设置set和get方法

编写新类时,可以直接操作简单的public属性,而不是实现set和get方法

如果访问对象的某个属性时,需要表现出特殊的行为,那就用@property来定义;

@property遵循最小惊讶原则,而不应该产生奇怪的副作用。

@property执行得迅速一点,缓慢复杂工作放到普通的方法里。

第30条 考虑用@property来为属性添加新功能

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

编译器在一个类的实例字典中找不到这个属性时,会调用__getattr__方法。

访问属性时,每次都会访问__getattribute__

第32条 __getattr__、__getattribute__、__setattr__

__getattr__:当访问某个类的实例变量,不存在时,会回调此函数

__getattribute__:访问某个类的实例变量时,每次都会回调

__setattr__:设置某个类的实例变量前会回调此函数

通过这些函数就可以按需进行动态地对实例属性进行修改了。

如果要在__getattribute__、__setattr__中访问实例属性,不能直接self访问,这样会不断循环。要使用super()

第33条 用元类来验证子类

python把子类的整个class加载后,就会调用其元类的__new__方法,可以在这个__new__方法里添加子类的验证逻辑。

Python2:

代码语言:javascript
复制
class Meta(type):    
    def __new__(meta, name, bases, class_dict):
class MyClasspython2(object):    
    __meta__ = Meta

python3

代码语言:javascript
复制
class Meta(type):
    def __new__(meta, name, bases, class_dict):
        Return type.__new__(meta, name, bases, class_dict)
Class MyClass(object, metaClass=Meta):
    stuff = 123

meta:元类

name:子类名

bases:父类元组

class_dict:class里面的一些东西

第34条 用元类来注册子类

举了个序列化和反序列化的例子

在构建模块化python程序时,类的注册是一种很有用的模式。类的注册可以放在元类中。只要基类的元类里实现了注册,那么子类继承基类时就无需再注册了。

第35条 用元类来动态赋值类的属性

借用元类,我们可以在某个类完全定义好之前,率先修改类的属性。

Orm中定义数据库中某个表的类,里面的Field,实现属性值为Filed的名字。这个在类的父类中的元类中,获取到所有属性值,然后将Filed的值赋好。

五、并发和并行

第36条 用subprocess模块来管理子进程

第37 条 多线程适用于io阻塞较多的场景,多进程用于cpu较多的场景 

由于GIL全局解释器锁存在,每个时刻其实只能一个线程执行。因此计算型任务不适合适用多线程,IO等待型任务适合多线程。

第38 条 多线程加锁

代码语言:javascript
复制
class Test():
    def __init__(slef):
        self.lock = Lock()
        self.count = 0
    def increment(self, offet):
        with self.lock:
            Self.count += offet

第39条 用Queue来协调各线程间的工作

如同生成线一样,使用pipeline 的思想,利用生产者消费者模型,将任务分发、传递最终合并。

自己实现由几个问题:某个阶段持续等待;如何停止工作线程、如何防止内存膨胀

可以使用Queue

第40条 使用concurrent.futures来实现真正的并行计算

底层使用multiprocessing来进行多进程,每个进程都有独立的GIL。

pool = ProcessPoolExecutor(max_workers=2)

results = list(pool.map(function, numbers))

ProcessPoolExecutor类会利用multiprocessing模块提供的底层机制:

  • 1.把numbers中的每一项输入数据都传给map;
  • 2.用pickle模块对数据进行序列化,将其变成二进制形式;
  • 3.通过本地套接字,将序列化后的数据从主进程,发送到子解释器所在进程;
  • 4.在子进程中,用pickle对二进制数据进行反序列化操作,将其还原为python对象;
  • 5.引入包含gcd函数的那个python模块;
  • 6.各子进程分别并行地对自己的数据执行gcd函数;
  • 7.将结果进行序列化操作,转变为字节;
  • 8.将这些字节通过socket复制到主进程中。
  • 9.主进程将字节反序列化为python对象;
  • 10.最后将每条子进程中的计算结果合并到一份列表。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二、函数部分
    • 第14条 尽量用异常来表示特殊情况,而不是None等值
      • 第15条了解如何在闭包里使用外面域的变量
        • 第16条 可以用生成器来改写返回列表的函数
          • 第17条 生成器作为参数的时候要注意
            • 第18条 用可变参数,来防止参数过多
              • 第19条 用关键字参数来设置可选参数
                • 第20条 动态的默认参数可以用None和注释来描述
                  • 第21条 确保调用者使用关键字参数
                  • 三、 类部分
                    • 第22条 尽量用辅助类来维护程序的状态,而不要用字典或元组
                      • 第23条  简单的接口可以接受函数而不是类
                        • 第24条 以@classmethod形式去通用的构建对象
                          • 第25条 用super初始化父类
                            • 第26条 只在使用Mixin制作工具类时,进行多重继承
                              • 第27条 类中属性多用public,少用private
                                • 第28条 自定义容器类,可以继承collections.abc来做
                                • 四、 元类及属性
                                  • 第29条  直接操作属性,而不是设置set和get方法
                                    • 第30条 考虑用@property来为属性添加新功能
                                      • 第31条 用描述符descriptor来改写需要复用的@property方法
                                        • 第32条 __getattr__、__getattribute__、__setattr__
                                          • 第33条 用元类来验证子类
                                            • 第34条 用元类来注册子类
                                              • 第35条 用元类来动态赋值类的属性
                                              • 五、并发和并行
                                                • 第36条 用subprocess模块来管理子进程
                                                  • 第37 条 多线程适用于io阻塞较多的场景,多进程用于cpu较多的场景 
                                                    • 第38 条 多线程加锁
                                                      • 第39条 用Queue来协调各线程间的工作
                                                        • 第40条 使用concurrent.futures来实现真正的并行计算
                                                        相关产品与服务
                                                        容器服务
                                                        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                        领券
                                                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档