美文网首页Python
Effective Python 学习笔记 4

Effective Python 学习笔记 4

作者: coder前行 | 来源:发表于2019-08-04 13:48 被阅读0次

    Effective Python 学习笔记 4

    尽量使用异常来表示特殊情况,而不要返回None

        _表示用不到的变量
    

    要点

    1. 用None这个返回值来表示特殊意义的函数,很容易使调用者犯错,以为None和0及空字符串之类的值,在表达式里面都会评估为False
    2. 函数遇到特特殊情况时应该抛出异常,而不是返回None

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

        '''
            eg. 有一份列表,其中元素都是数字,现在对其排序,要把出现在某个群组内的数字,放在群组外的那些数字之前。
        '''
        def sort_pri(values, group):
            def helper(x):
                if x in group:
                    return (0, x)
                return (1, x)
            values.sort(key = helper)
            '''
                上述函数成立的原因:
                    1. 函数是一等对象(first-class object)
                    2. python支持闭包
                    3. python中使用特殊的规则来比较两个元组。它首先比较各元组中下标为0的对应元素,如果相等,再比较下标为1的元素,如果还是想等,就继续依次比较。
            '''
    
        numbers = [8, 3, 1, 2, 5, 4, 7, 6]
        group = {2, 3, 5, 7}
        sort_pri(numbers, group)
        print(numbers)
        >>> [2, 3, 5, 7, 1, 4, 6, 8]
    

    要点

    1. 对于定义在某作用域内的闭包来说,它可以引用这些作用域中的变量
    2. 使用默认方式对闭包内的变量赋值,不会影响外围作用域的同名变量
    3. 在python 3中,程序可以在闭包内用nonlocal语句来修饰某个名称,使该闭包能够修改外围作用域中的同名变量
    4. 除了简单的函数,尽量不要使用nonlocal语句

    考虑使用生成器来改写直接返回列表的函数

        # eg.返回字符串中英文单词的首字母和其下标
        def index_words(text):
            result = []
            if text:
                result.append(0)
            for index, letter in enumerate(text):
                if letter == ' ':
                    result.append(index + 1)
            return result
    
        words = 'I am python'
        re = index_words(words)
        print(re)
        >>> [0, 2, 5]
    

    以上程序的问题:

    1. 代码拥挤,每次找到新的结果,都要调用append方法。而我们真正强调的不是对append的调用,而是该方法给列表中添加的那个值且函数首位都要对resut进行创建和返回
        # 生成器改写
        def index)words_iter(text):
            if text:
                yield 0
            for index, letter in enumerate(text):
                if letter == ' ':
                    yield index + 1
    
            ### ···
    
            re = list(index_words_iter(address))
    
    1. index_words函数在它返回前,要把所有结果都放在列表中。如果数据量非常大,那么程序可能会耗尽内存。用生成器改写后,可以应对任意长度的输入数据

    要点

    1. 使用时生成器比用list返回结果更加清晰
    2. 由生成器函数所返回的那个迭代器,可以把生成器函数体中,传给yield表达式的那些值,逐次生产出来
    3. 无论数据量多大,生成器都能产生一系列输出,不会对内存造成压力

    在参数上面迭代时要多加小心

        细节见书本第17条
    

    要点

    1. 如果参数是迭代器,那么可能会导致奇怪的行为并错失某些值
    2. python的迭代器协议,描述了容器和迭代器应该如何与iter和next内置函数、for循环及相关表达式相互配合
    3. iter方法时限为生成器,即可定义自己的容器类型
    4. 想判断某个值是迭代器还是容器,可以拿该值为参数,两侧调用iter函数,若结果相同,则是迭代器,调用内置的next函数,即可令该迭代器前进一步

    用数量可变的位置参数减少视觉杂讯

        令函数接受可选位置参数(由于这种参数习惯上写为*args,所以又称为star args,星号参数),能够使代码更加清晰,并减少视觉杂讯(visual noise)。
    
        visual noise:一种比喻,意思是使代码看起来不要太过杂乱,以强调其中的重要内容。
    

    出现的问题

    1. 变长参数在传给函数时,总是先转化为元组。这就意味着,如果用带有*操作符的生成器为参数,来调用这种参数,python必须把该生成器完整迭代一轮,并把所生成的每个值,都放入元组之中。这可能会消耗大量内存。所以只有当我们确定参数个数较少时,才采用这种写法
    2. 如果以后要给函数添加新的位置参数,那就必须修改原来调用该函数的那些旧代码

    要点

    1. def语句中用*args,即可令函数接受数量可变的位置参数
    2. 调用函数时,可以采用*操作符,把序列中的元素当成位置参数,传给该函数
    3. 对生成器使用*操作符,可能导致内存耗尽
    4. 在已经接受*args参数的函数上继续添加位置参数,可能会产生难以排查的bug

    用关键字参数来表达可选行为

        def func(arg1, arg2):
            return arg1 + arg2
        # 以下写法等效
        func(1, 1)
        func(arg1 = 1, 1)
        func(1, arg2 = 1)
        func(arg1 = 1, arg2 = 1)
    

    关键字参数的好处

    1. 易于理解,参数含义与参数值都呈现在面前
    2. 可以在函数中提供默认值
    3. 它可以提供一种扩充函数参数的有效方式,使得扩充之后的函数依然能与原有的那些调用代码兼容

    要点

    1. 函数参数可以按照位置或关键字来指定
    2. 只是用位置参数来调用函数,可能会导致这些参数数值含义不够明确,而关键字参数则能够阐明每个参数的意图
    3. 给函数添加新行为时,可以使用带默认值的关键字参数,以便与原有的函数点用代码保持兼容
    4. 可选的关键字参数,总是应该以关键字形式来指定,而不是以位置参数的形式来指定

    参考资料

    1. python 闭包和装饰器详解
    2. Python3 List sort()方法
    3. 深入理解 Python yield

    相关文章

      网友评论

        本文标题:Effective Python 学习笔记 4

        本文链接:https://www.haomeiwen.com/subject/qcfydctx.html