python开发

编写高质量python代码的59个方法

2018-02-14  本文已影响22人  宝宝家的隔壁老王
1、确认python的版本
2、遵循PEP8风格指南
3、了解bytes,str与unicode的区别
4、用辅助函数取代复杂的表达式
5、了解切割序列的办法
6、单次切片操作时,不要同时指定start,end和stride
7、用列表推导代替 map 和 filter
8、不要使用含有两个以上表达式的列表推导
9、用生成器表达式来改写数据量比较大的列表推导
10、使用 enumerate 取代 range
11、用zip函数同时遍历两个函数
12、不要在for和while循环后面写else语句
13、合理利用try/except/else/finally结构中的每个代码块
14、尽量用异常表示特殊情况,而不要返回None
15、了解如何在闭包里使用外围作用域中的变量
16、用生成器来改写直接返回列表的函数
17、在参数上面迭代,要多加小心
18、用数量可变的位置参数减少视觉杂讯
19、用关键字参数表达可选的行为
20、用None和文档字符串来描述具有动态默认值的参数
def log(message, when=datetime.now()):
    print('%s: %s' % (when, message))
21、用只能以关键字形式指定的参数来确保代码明晰
22、尽量用辅助类来维护程序的状态,而不要用字典或元组
23、简单的接口应该接受函数,而不是类的实例
24、以@classmethod形式的多态去通用的构建对象
25、用 super 初始化父类
26、只有使用Mix-in组件制作工具类时进行多重继承
27、多用public属性,少用private属性
28、继承collections.abc以实现自定义容器类型
29、用纯属性取代set和get方法
class A:
    def __init__(self, name):
        self.name = name
    @property
    def name(self):
        return self._name
        
    @name.setter
    def name(self, name):
        self._name = name
30、考虑使用@property来代替属性重构
31、用描述符来改写需要复用的@property方法
# 实现 
__get__(self, instance, cls), 
__set__(self, instance, value)
方法即实现了描述符协议。其中实现了__set__方法的描述器为覆盖型描述器,覆盖型描述符同样会覆盖对实例属性的覆盖操作
不管描述符是不是覆盖型描述符,对类属性赋值都能覆盖描述符
32、用getattribute, setattr实现按需生成属性
33、用元类来验证子类
class Meta(type):
    def __new__(meta, name, bases, class_dict):
        print(meta, name, bases, class_dict)
        return type.__new__(meta, name, bases, class_dict)
        
# py3
class MyClass(object, metaclass=Meta):
    pass

# py2
class MyClass(object):
    __metaclass__ = Meta
    
"""
1、通过元类可以在生成子类对象之前,先验证子类的定义是否是合乎规范
2、Python系统把子类的整个class语句处理完毕后,就会调用其元类的__new__方法
"""
34、用元类来注册子类
1、构建模块化的Python程序时,类的注册是一种很有用的模式
2、开发者每次从基类中继承子类时,基类的元类都可以自动运行注册代码
3、通过元类实现类的注册,确保子类不会遗漏,避免后续的错误
35、用元类注解类的属性(结合修饰符,很牛逼)
class Field:
    def __init__(self):
        self.name = None
        self.internal_name = None
    
    def __get__(self, instance, instance_type):
        return getattr(instance, self.internal_name, '')
    
    def __set__(self, instance, value):
        if value != 'py':
            raise ValueError('must be py')
        setattr(instance, self.internal_name, value)

class Meta(type):
    def __new__(meta, name, bases, class_dict):
        for key, value in class_dict.items():
            if isinstance(value, Field):
                value.name = key
                value.internal_name = '_' + key
        cls = type.__new__(meta, name, bases, class_dict)
        return cls

class Person(metaclass=Meta):
    name = Field()
    gender = Field()
    age = Field()

"""
1、借助元类,可以在某个元类完全定义好之前,率先修改类的属性
2、描述符与元类有效的组合起来,便于对某种行为作出修饰,或在程序运行时探查相关信息
3、把元类和描述符相结合,可以在不使用weakref模块的前提下,避免内存泄露
"""
36、用subprocess模块管理子进程
# 不建议使用该模块
37、使用线程来执行阻塞式I/O,但不要用它做平行计算
1、受到全局解释器的限制,多条Python线程不能再多个CPU核心上面平行的执行字节码
2、Python多线程可以轻松的模拟出同一时刻执行多任务的效果
3、平行的执行多个系统的调用,使得程序能够在执行阻塞式I/O操作的同时,执行一些运算操作
38、在线程中使用Lock来防止数据竞争
1、Python确实有全局解释器,但是在编写自己的程序时,依然要设法防止多个线程争用同一份数据。
2、在不加锁的前提下,允许多条线程修改同一个对象,程序的数据结构可能被破坏
3、Python内置的threading模块中,有个名叫Lock的类,他用标准的方式实现了互斥锁
39、使用Queue协调各线程之间的工作
40、考虑用协程来并发的运行多个函数
41、考虑使用concurrent.futures来实现真正的平行计算
1、引发cpu性能瓶颈的那部分代码,用c语言扩展来写,可在尽量发挥Python特性的前提下,有效的提升程序的执行速度,但是工作量比较大,而且很有可能会引入bug
2、multiprocessing模块提供了强大的工具。对于某些类型的任务来说,开发者只需要编写少量代码,即可实现平行计算
3、若想利用强大的multiprocess模块,最恰当的做法就是通过内置的concurrent.futures模块及其ProcessPoolExecutor类来使用它
42、用functions.wraps定义函数修饰器
def trace(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # ...
    return wrapper
43、考虑以contextlib和with语句来改写可复用的try/finally代码
1、可以通过 with 语句来改写 try/finally 块中的逻辑,以便提升复用程度,使代码更1加整洁
2、内置的 contextlib 模块提供了名为 contextmanager 的装饰器,开发者只需要用它来装饰自己的函数(函数中需要增加 yield 语句),即可令该函数支持 with 语句
3、情景管理器可以通过 yield 语句向 with 语句返回一个值,此值会赋给由 as 关键字所指定的变量。
44、用copyreg实现可靠地pickle操作
45、应该用datetime模块来处理本地时间,而不是time模块
1、不要用time模块在不同时区之间进行转换
46、使用内置算法和数据结构
# 1、双向队列 collections.deque FIFO
>>> d = deque()
>>> d.append(1)
>>> d.append(2)
>>> d.pop()  # 2

# 2、有序字典 collections.OrderDict
# 按照键的插入顺序,来保留键值对在字典中的次序

# 3、带有默认值的字典 collections.defaultdict
>>> dct = defaultdict(int)
>>> dct['score'] += 1

# 4、堆队列 heapq
>>> a = []
>>> heap.heappush(a, 5)
>>> heap.heappush(a, 3)
>>> heap.heappush(a, 7)
>>> heappop(a)  # 3
>>> heappop(a)  # 5
>>> heappop(a)  # 7

# 5、二分查找
>>> import bisect
>>> x = list(range(10**8))
>>> i = x.index(99123400)
>>> # 二分法
>>> i = bisect.bisect_left(x, 99123400)

# 6、与迭代器有关工具
>>> # itertools
>>> # chain: 将多个迭代器顺序连成一个迭代器
>>> # cycle
>>> # tee
>>> # zip_longest
>>> # islice
>>> # takewhile
>>> # dropwhile
>>> # filterfalse
>>> # product
>>> # permutations
>>> # combination
47、重视精度的场合应该使用 decimal
Decimal 类非常适合用在那种对精度要求很高,且对摄入行为要求很严的场合,例如,设计货币基金计算的场合
48、学会安装由Python开发者社区所构建的模块
49、为每个函数,类和模块编写文档和字符串
50、用包来安排模块,并提供稳固的API
1、python 包是一种含有其他模块的模块。我们可以把包代码划分成各自独立且互不冲突的名称空间,使得每块代码都能具备独立的绝对模块名称
2、把外接可见的名称列在名为 __init__ 的特殊属性里,即可为包提供一套明确的API
3、如果想隐藏某个包的内部实现,可以在 __init__ 文件中,只把外界可见的名称引入进来,或给仅限内部使用的那些名称添加下划线前缀
51、为自己的模块定义根异常以便调用者与 API 隔离
1、为模块定义根异常,可以把 API 的调用者与模块的API相隔离
2、调用者使用 API 时,通过捕获根异常,来发现调用代码中隐藏的bug
3、调用者可以通过捕获 Python 的 Exception 基类,来帮助模块的研发者找寻 API 实现代码中的 bug
52、适当的方式打破循环依赖关系
53、用虚拟环境隔离项目,并重建其依赖关系
54、考虑模块级别的代码来配置不同的部署环境
55、通过 repr 字符串来输出调试信息
56、用 unittest 测试全部代码
57、考虑用pdb实现交互调试
58、先分析性能,然后再优化
59、用 tracemalloc 来掌握内存的使用及泄露情况
上一篇下一篇

猜你喜欢

热点阅读