1、善用变量来改变代码质量

变量命名

  • 变量要有描述性,不能太宽泛

    • BAD:day, host, cards, temp
    • GOOD:day_of_week, hosts_to_reboot, expired_cards
  • 变量名最好让人猜出类型
    • Python是动态语言,没有变量类型声明,只能根据上下文猜测
    • Boolean:is_superuser, has_error, allow_vip
    • int/float:user_id, user_count, number_of_apples
  • 适当使用“匈牙利命名法”
    • 把变量缩写放在变量名的最前面
    • students指向一个包含Person对象的list
    • students->pl_students
  • 变量名尽量短但不要太短
    • 两三个单词左右
    • 避免只有一两个字母的短名字
  • 其他
    • 同一段代码内不要使用过于相似的变量名,如user1, user2, user3
    • 不要使用带否定含义的变量名,is_not_normal->is_special

变量使用

  • 保持一致性

    • 不要用一个变量名一会表示str,一会表示list
  • 尽量不要用globals()/locals()
  • 变量定义尽量靠近使用
  • 合理使用namedtuple/dict让函数返回多个值
  • 控制单个函数内的变量数量
  • 及时删掉没用的变量
  • 需要的时候再定义变量

2、编写条件分支代码的技巧

最佳实践

  • 避免多层分支嵌套

    • 过多的层次缩进影响代码可读性
    • 用return/raise提前结束分支
  • 封装过于复杂的逻辑判断
    • 过多的not/and/or影响代码可读性
    • 用函数封装具体判断
  • 留意不同分支下的重复代码
    • 重复代码令代码使用者难以区分不同分支的区别
    • 利用Python的动态特性改善代码
  • 谨慎使用三元表达式
    • 用 x and a or b 模拟
    • 用 if/else 替换
    • 只用三元表达式处理简单的逻辑分支

常见技巧

  • 使用“的摩根定律”

    • not A or not B -> not( A and B )
  • 自定义对象的“布尔真假”
    • Python对象具有布尔值,适当利用可简化分支代码
    • 魔法方法(user-defined method)__bool__和__len__
  • 条件判断中使用all()/any()
    • all(seq):仅当seq中所有对象为真时返回True
    • any(seq):只要seq中有对象为真就返回True
  • 使用try/while/for中的else分支

常见陷阱

  • 与None值的比较
  • 留意and和or的运算优先级

3、使用数字与字符串的技巧

序言

  • Python中的三种数据类型:整型(int)、浮点型(float)和复数(complex)
  • Python中的整型不区分有无符号,且永不溢出

最佳实践

  • 少写数字字面量(integer literal),即那些直接出现在代码里的数字,对于会重复出现的数字,可利用枚举类型enum定义
  • 少用裸字符串处理,即只用基本运算操作字符串,可用对象化的方式构建和编辑,如SQLAlchemy、lxml、JSON
  • 不必预计算字面量表达式,Python解释器会自动预先计算

实用技巧

  • 布尔值其实也是“数字”,如 True+1=2
  • 改善超长字符串的可读性,使用\或+拆分,或用()将长字符串包起来
  • 在多级缩进里插入多行字符串时,可用textwrap调整缩进
  • 别忘了“r”开头的内建字符串函数(从右往左)
  • 使用无穷大float("int")和float("-int")

常见误区

  • value+=1 并非线程安全,被Python解释器执行时,不是原子操作
  • 字符串拼接(+=)并不慢

4、容器的门道

底层看容器

  • Python常用的内建容器:列表(list)、元组(tuple)、字典(dict)、集合(set)
  • 避免频繁扩充/创建新列表,列表内存是按需分配的,现有内存不够时会触发扩容操作
  • 多使用yield关键字,返回生成器对象
  • 尽量使用生成器表达式替代列表推导表达式
  • 尽量使用模块提供的懒惰对象
  • 在列表头部操作多的场景使用deque模块
  • 使用集合/字典判断成员是否存在

高层看容器

  • Python是“鸭子类型”语言,只某对象满足了该类型的接口规范,就可以被当做该类型的对象使用
  • 各个容器类型实现的接口协议定义了容器,不同的容器是“是否可迭代”、“是否可修改”、“有没有长度”等各种特性的组合
  • 写代码时应更多关注容器的抽象属性,而非容器类型本身
  • 面向接口而非具体实现编程

常用技巧

  • 使用元组改善分支代码:二分查找模块bisect
  • 在更多地方使用动态解包:使用*或**将可迭代对象“解开”
  • 最好不用“获取许可”,也无需“要求原谅”:使用collections.defaultdict,而非捕捉异常
  • 使用next()函数:接收一个迭代器作为参数,返回迭代器的下一个元素,配合生成器使用
  • 使用有序字典去重:collections.OrderedDict

常见误区

  • 当心已经枯竭的迭代器:遍历完后再遍历,就没有结果了
  • 别在循环体内修改被迭代对象:遍历的同时修改会出错,应使用一个空列表保存结果,或使用yield返回生成器

5、让函数返回结果的技巧

编程建议

  • 单个函数不要返回多种类型(单一职责)
  • 使用partial构造新函数
  • 抛出异常,而不是返回结果与错误
  • 谨慎使用None返回值,仅在以下情况使用

    • 作为操作类函数的默认返回值
    • 作为某些“意料之中”的可能没有的值
    • 作为调用失败时代表“错误结果”的值,函数签名(名称与参数)与None返回值之间是否存在一种“意料之中”的暗示
  • 合理使用“空对象模式”,即使用一个符合正常结果接口的“空类型”来代替空值返回/抛出异常,以降低调用方处理结果的成本
  • 使用生成器函数代替返回列表
  • 限制递归的使用,Python对递归支持有限,尽量采用循环实现

6、异常处理的三个好习惯

  • 异常处理工作由“捕获”和“抛出”两部分组成

三个建议

  • 只做最精确的异常捕获

    • 永远只捕捉可能会抛出异常的语句块
    • 尽量只捕获精确的异常类型,而不是模糊的Exception
  • 别让异常破坏抽象一致性
    • 让模块只抛出与当前抽象层级一致的异常
    • 在必要的地方进行异常包装与转换
  • 异常处理不应喧宾夺主 
    • 使用上下文管理器(context manager)

7、编写地道循环的两个建议

  • for <item> in <iterator> 和 while <condition>
  • 使用函数修饰被迭代对象来优化循环
    • 使用product扁平化多层嵌套循环
    • 使用islice实现循环内隔行处理,islice(seq, start, end, step)
    • 使用takewhile替代break语句,takewhile(predicate, iterable)
    • 使用生成器编写自己的修饰函数
  • 按职责拆解循环内的复杂代码块
    • 复杂循环体如何应对新需求,避免循环体内的代码膨胀
    • 使用生成器函数解耦循环体,隔离不同职责的代码块

8、装饰器使用技巧

  • 装饰器(Decorator)可以在函数外部修改函数

最佳实践

  • 尝试用类来实现装饰器

常见错误

  • “装饰器”并不是“装饰器模式”
  • 用functools.wraps()装饰内层函数
  • 修改外层变量使用nonlocal

9、一个关于模块的小故事

  • Module是用来组织Python代码的基本单位
  • 合理的模块结构与分层非常重要
  • 整个项目内的模块间依赖关系流向,应该是单向的,不能有环形依赖存在

10、做一个精通规则的玩家

11、高效操作文件的三个建议

  • 使用pathlib模块
  • 掌握如何流式读取大文件
  • 设计接收文件对象的函数

12、写好面向对象代码的原则

Python对OOP的支持

  • 没有严格的类私有成员
  • 没有接口(interface)对象

SOLID设计原则

  • S(单一职责原则):一个类应该只有一种被修改的原因
  • O(开放-关闭原则):类应该对改动关闭,对扩展开放
  • L(李氏替换原则):子类应该可以任意替换父类被使用
  • D(依赖倒置原则):高层模块不应依赖低层模块,二者都应依赖于抽象
  • I(接口隔离原则):客户应该不依赖于他不使用的方法

参考

闭包

https://www.liaoxuefeng.com/wiki/1022910821149312/1023021250770016

https://blog.csdn.net/weixin_43586120/article/details/89456183

[Python] Python工匠(Github)的更多相关文章

  1. Python实用案例,Python脚本,Python实现自动监测Github项目并打开网页

    往期回顾 Python实现文件自动归类 前言: 今天我们就利用Python脚本实现Github项目的更新,提醒方式是邮箱.直接开整~ 项目地址: https://github.com/kenwoodj ...

  2. python --- Python中的callable 函数

    python --- Python中的callable 函数 转自: http://archive.cnblogs.com/a/1798319/ Python中的callable 函数 callabl ...

  3. Micro Python - Python for microcontrollers

    Micro Python - Python for microcontrollers MicroPython

  4. 从Scratch到Python——python turtle 一种比pygame更加简洁的实现

    从Scratch到Python--python turtle 一种比pygame更加简洁的实现 现在很多学校都开设了Scratch课程,学生可以利用Scratch创作丰富的作品,然而Scratch之后 ...

  5. 从Scratch到Python——Python生成二维码

    # Python利用pyqrcode模块生成二维码 import pyqrcode import sys number = pyqrcode.create('从Scratch到Python--Pyth ...

  6. [Python]Python 使用 for 循环的小例子

    [Python]Python 使用 for 循环的小例子: In [7]: for i in range(5): ...: print "xxxx" ...: print &quo ...

  7. [python]python 遍历一个list 的小例子:

    [python]python 遍历一个list 的小例子: mlist=["aaa","bbb","ccc"]for ss in enume ...

  8. [Python]Python日期格式和字符串格式相互转换

    由字符串格式转化为日期格式的函数为: datetime.datetime.strptime() 由日期格式转化为字符串格式的函数为: datetime.datetime.strftime() # en ...

  9. [python]Python 字典(Dictionary) update()方法

    update() 函数把字典dict2的键/值对更新到dict里.如果后面的键有重复的会覆盖前面的语法dict.update(dict2) dict = {'Name': 'Zara', 'Age': ...

随机推荐

  1. 【JVM进阶之路】八:性能监控工具-命令行篇

    定位问题的时候,知识.经验是关键基础,数据是依据,工具是运用知识处理数据的手段. 在实际的故障排查.性能监控中,常常是操作系统的工具和Java虚拟机的工具结合使用. 1.操作系统工具 1.1.top: ...

  2. docker部署kafka集群

    利用docker可以很方便的在一台机子上搭建kafka集群并进行测试.为了简化配置流程,采用docker-compose进行进行搭建. kafka搭建过程如下: 编写docker-compose.ym ...

  3. [高精度]P1096 Hanoi 双塔问题

    Hanoi 双塔问题 题目描述 给定A.B.C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形). 现 ...

  4. 开源服务器设计总计(plain framework2020年总计)

    2020年注定会被历史铭记,世界遭受着一场前所未有的灾难,这种灾难到现在还在持续.还记得19年末的时候,那时候听到一点点消息,哪里想得到年关难过,灾难来的让人猝不及防.由于疫情防控,2020年感觉转瞬 ...

  5. 【C/C++】面相对象开发之封装

    封装继承多态是面向对象程序开发的基础概念.是实现面向对象的基本要素. 封装 程序开发,最核心价值,是数据. 程序其实是读取数据,操作数据,保存数据等一系列操作. 那么经过良好组织过的数据,将使编程事半 ...

  6. Dynamics CRM字段安全配置文件

    在实施Dynamics CRM的过程中,有些需求会提到部分字段针对特殊的人员或者团队进行显示.更新以及创建的需求的控制.这里我们就需要用到字段安全性文件这个功能.此功能针对具体实体的字段进行配置可以达 ...

  7. 【转载】C# get 与set的一些说明

    转载 在面向对象编程(OOP)中,是不允许外界直接对类的成员变量直接访问的,既然不能访问,那定义这些成员变量还有什么意义呢?所以C#中就要用set和get方法来访问私有成员变量,它们相当于外界访问对象 ...

  8. .netcore ioc 循环依赖问题及其相关思考之DispatchProxy

    .netcore引入了ioc机制让开发人员逐步习惯从过去的各种new对象变成通过IOC框架来管理对象的生命周期.这样当我们需要某个对象的时候,我们一般在构造函数里申明该对象的接口,即可通过ioc容器创 ...

  9. php的类

    类成员中:属性.类常量和方法都可以无限定义,但是定义的原则是相关性.除了以上三个类成员,不能在类结构{}中直接写其他任何代码 PHP类结构中有三种成员:属性.方法和类常量 类结构中只能有三种成员,不限 ...

  10. linux系统调用号查询(pwn)

    做pwn题时遇到程序使用了64位系统调用号:59和15,这里做一下记录 在线查询链接:https://syscalls.w3challs.com/ 分为32位和64位,链接中还有arm.mips等架构 ...