Effective Python 學習筆記 4

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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。