【Python】《Effective Python》 读书笔记 (一)

# -*- coding: utf-8 -*-

from datetime import datetime
from time import sleep
from urllib.parse import parse_qs
import json


def example_1():
    """
    确认自己所用的Python版本
    * Python3 和 Python2 不兼容
    :return:
    """
    pass


def example_2():
    """
    遵循PEP8风格指南
    * 不要通过检测长度的方法, 如 if len(somelist) == 0, 而是 if not somelist
    * 引入模块时, 应使用绝对名称, 而不是相对名称,如 from bar import foo 而不是
    import foo.
    * 如果一定要用相对名称, 就采用明确写法 from . import foo
    :return:
    """
    pass


def example_3():
    """
    了解bytes,str和unicode的区别
    * Python3, bytes 包含原始8位值, str的实例包含Unicode字符
    * Python2, str 包含原始8位值, 而Unicode的实例包含Unicode字符
    * Python3的str实例 和Python的Unicode实例都没有和特定的二进制编码形式相关联
    :return:
    """
    pass


def example_4():
    """
    用辅助函数来取代复杂的表达式
    :return:
    """
    my_values = parse_qs("red=5&blue=0&green=", keep_blank_values=True)
    print(my_values)
    # 如果键的值是空就返回0
    green = my_values.get("green", [''])[0] or 0
    print(green)  # 输出 0
    pass


def example_5():
    """
    了解切割序列的方法
    :return:
    """
    a = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    print(a[2:])  # 输出 ['c', 'd', 'e', 'f', 'g']


def example_6():
    """
    在单次切片操作内, 不要同时指定start、end 和 stride(步进值)
    * 如果非要用stride, 尽量采用负值(或考虑itertools的islide方法)
    :return:
    """
    a = ['rad', 'orange', 'yellow', 'green', 'blue', 'purple']
    odds = a[::2]  # 表示从头部开始, 每两个元素选取一个, 如果是负号则是从尾部开始
    events = a[1::2]
    print(odds)  # 偶数索引
    print(events)  # 奇数索引

    x = b'mongoose'
    y = x[::-1]  # 字符反转技巧, 注意仅对ASCII字有用, UTF-8等无法奏效
    print(y)


def example_7():
    """
    用列表推导来取代map和filter
    :return:
    """
    a = [1, 2, 3, 4, 5]
    print([x ** 2 for x in a])  # 列表推导表达更清晰
    print(list(map(lambda x: x ** 2, a)))

    even_squares = [x ** 2 for x in a if x % 2 == 0]
    print(even_squares)
    alt = map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, a))
    print(list(alt))


def example_8():
    """
    不要使用含有两个以上表达式的列表推导
    * 因为难以理解
    :return:
    """
    pass


def example_9():
    """
    用生成器表达式来改写数据量较大的列表推导
    :return:
    """
    value = [len(x) for x in open('leecode.py')]  # 问题数据量大,内存激增
    print(value)
    it = (len(x) for x in open('leecode.py'))  # 改用生产器, 返回可迭代对象, 但注意迭代器有状态,仅能迭代一轮
    while True:
        try:
            x = next(it)
            print(x)
        except StopIteration:
            break


def example_10():
    """
    尽量用enumerate来取代range
    * 下标和序列元素都能一次获取
    :return:
    """
    flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
    for i, flavor in enumerate(flavor_list, 1):
        print("%d: %s" % (i + 1, flavor))


def example_11():
    """
    用zip函数同时遍历两个迭代器
    * 比如两个list中的元素是一对一的关系
    :return:
    """
    names = ['Cecilia', 'Lise', 'Marie']
    letters = [len(n) for n in names]

    longest_name = None
    max_letters = 0

    for name, count in zip(names, letters):
        if count > max_letters:
            longest_name = name
            max_letters = count
    print(longest_name)


def example_12():
    """
    不要在for和while循环后面写else块
    * Python可以这样做, 但是你不要这样做
    :return:
    """
    pass


def example_13():
    """
    合理利用try/except/else/finally结构中的每个代码块
    :return:
    """
    UNDEFINED = object()

    def divide_json(path):
        handle = open(path, 'r+')
        try:
            data = handle.read()
            op = json.load(data)
            value = (op['numerator'], op['denominator'])
        except ZeroDivisionError as e:
            return UNDEFINED
        else:
            op['result'] = value
            result = json.dumps(op)
            handle.seek(0)
            handle.write(result)
            return value
        finally:
            handle.close()


def example_14():
    """
    尽量用异常来表示特殊情况, 而不用返回None
    * 容易让调用者写出错误的代码,到底是程序异常的None? 还是自己数据的不合理?
     一个例子就是除法, 除数为0
    * 解决办法之一: 使用元祖,一个放数据,一个放成功状态(但是调用者可以用_忽略不去检测,也是比较尴尬)
    * 最好的解决就是抛异常给上一级
    :return:
    """


def example_15():
    """
    了解如何在闭包中使用外围作用域中的变量
    * 获取闭包内的数据, 使用nonlocal关键字(Python2不支持,但是有解决)
    :return:
    """
    pass


def example_16():
    """
    考虑用生成器来改写直接返回列表的函数
    * yield 关键字
    :return:
    """

    def index_words_iter(text):
        if text:
            yield 0
        for index, letter in enumerate(text):
            if letter == ' ':
                yield index + 1

    text = 'apple pink origin'
    result = list(index_words_iter(text))
    print(result)


def example_17():
    """
    在参数上面迭代时,要多加小心
    * 问题时迭代器迭代一次
    * 列表推导数据量大时, 内存激增
    * 解决一: 使用lambda, 每次都能产生新的迭代器
    * 最佳解决: 建立对象, 使用__iter__ 内置函数
    :return:
    """
    pass


def example_18():
    """
    用数量可变的位置参数减少视觉杂讯
    :return:
    """

    def log(message, *values):
        if not values:
            print(message)
        else:
            values_str = ', '.join(str(x) for x in values)
            print("%s: %s" % (message, values_str))

    favorites = [7, 17, 99]
    log("Favorite colors", *favorites)  # 列表加上*号, Python 会把列表里的元素视为位置参数


def example_19():
    """
    用关键字参数来表达可选行为
    * 一个除法函数, 谁是除数? 谁是被除数?
    :return:
    """
    pass


def example_20():
    """
     用None和文档字符串来描述具有动态默认值的参数
    :return:
    """

    def log(message, when=None):
        """

        :param message:
        :param when: datetime of when the message occurred.
                    Default to the present time.
        :return:
        """
        when = datetime.now() if when is None else when
        print('%s: %s' % (when, message))

    log('Hi there!')
    sleep(0.1)
    log('Hi again!')


def example_21():
    """
    只能用以关键字形式指定的参数来确保代码清晰
    :return:
    """

    def safe_division(number, divisor, ignore_overflow=False, ignore_zero_division=False):
        try:
            return number / divisor
        except OverflowError:
            if ignore_overflow:
                return 0
            else:
                raise
        except ZeroDivisionError:
            if ignore_zero_division:
                return float("inf")
            else:
                raise

    # 调用者可以根据自己的具体需要, 用关键字来覆盖Boolean标志的默认值, 以便跳过相关的错误
    safe_division(1, 10 ** 500, ignore_overflow=True)
    safe_division(1, 0, ignore_zero_division=True)


if __name__ == '__main__':
    example_18()
    # example_5()
    # example_20()
    # example_21()

猜你喜欢

转载自www.cnblogs.com/jzsg/p/11308074.html