Python---選擇正確的內置函數和標準庫實例(附代碼)

1:選擇正確的內置函數

Python有一個大型標準庫,但只有一個內置函數的小型庫,這些函數總是可用的,不需要導入。它們每一個都值得我們仔細研究,尤其是在其中一些函數的情況下,可以用什麼替代更好

1.1 使用enumerate()而不是range()進行迭代

有一個元素列表,您需要遍歷列表,同時訪問索引和值。
有一個名爲FizzBuzz的經典編碼面試問題可以通過迭代索引和值來解決。在FizzBuzz中,你將獲得一個整數列表,任務是執行以下操作:
(1)用“fizz”替換所有可被3整除的整數
(2)用“buzz”替換所有可被5整除的整數
(3)將所有可被3和5整除的整數替換爲“fizzbuzz”

# 普通用法,使用range()解決此問題

numbers = [45, 22, 14, 65, 97, 72]
for i in range(len(numbers)):
    if numbers[i] % 3 == 0 and numbers[i] % 5 == 0:
        numbers[i] = 'fizzbuzz'
    elif numbers[i] % 3 == 0:
        numbers[i] = 'fizz'
    elif numbers[i] % 5 == 0:
        numbers[i] = 'buzz'
numbers

運行結果:

在這裏插入圖片描述

Range允許你通過索引訪問數字元素,並且對於某些特殊情況也是一個很有用的工具。但在這種情況下,我們希望同時獲取每個元素的索引和值,更優雅的解決方案使用enumerate():

numbers = [45, 22, 14, 65, 97, 72]
for i,num in enumerate(numbers):
    if num % 3 == 0 and num % 5 == 0:
        numbers[i] = 'fizzbuzz'
    elif num % 3 == 0:
        numbers[i] = 'fizz'
    elif num % 5 == 0:
        numbers[i] = 'buzz'
numbers

運行結果:
在這裏插入圖片描述

此外,使用內置函數enumerate():
對於每個元素,enumerate()返回一個計數器和元素值。計數器默認爲0,也是元素的索引。不想在0開始你的計數?只需使用可選的start參數來設置偏移量

numbers = [45, 22, 14, 65, 97, 72]

for i,num in enumerate(numbers,start = 50):
    print(i,num)

運行結果:
在這裏插入圖片描述
我們可以看到,通過使用start參數,我們訪問所有相同的元素,從第一個索引開始,但現在我們的計數從指定的整數值開始。

1.2 使用遞推式構造列表而不是map()和filter()

讓我們首先看看我們如何構造對map()的調用以及等效的遞推構造列表:

numbers= [3, 2, 5, 1, 10, 7]
def square(x):
    return x*x

print(list(map(square,numbers)))

print([square(x) for x in numbers])

運行結果:
在這裏插入圖片描述
使用map()和列表推導的兩種方法都返回相同的值,但列表推導更容易閱讀和理解


numbers= [3, 2, 5, 1, 10, 7]
def is_old(x):
    return bool(x % 2)

print(list(map(is_old,numbers)))   # bool()和bool(0) 返回False,其他爲True

print(list(filter(is_old,numbers)))

print([x for x in numbers if is_old(x)])
                                    
print([square(x) for x in numbers if is_old(x)]) # 結合使用

運行結果:
在這裏插入圖片描述

就像在map中看到的那樣,filter和列表推導方法返回相同的值,但列表推導更容易理解。

1.3 使用f-Strings格式化字符串

Python有很多不同的方法來處理字符串格式化,有時候不知道使用哪個,f-strings支持使用字符串格式化迷你語言,以及強大的字符串插值。這些功能允許添加變量甚至有效的Python表達式,並在添加到字符串之前在運行時對它們進行評估。

def get_name_and_decades(name, age):
    return f"My name is {name} and I'm {age} years old."

print(get_name_and_decades("Maria", 31))

運行結果:
在這裏插入圖片描述

1.4 使用sorted()對複雜列表進行排序

大量的編碼面試問題需要進行某種排序,並且有多種有效的方法可以進行排序。除非你需要實現自己的排序算法,否則通常最好使用sorted()。 你可能已經看到了排序的最簡單用法,例如按升序或降序排序數字或字符串列表:
默認情況下,sorted()已按升序對輸入進行排序,而reverse關鍵字參數則按降序排序

sorted([6,5,3,7,2,4,1])
# 輸出結果:[1, 2, 3, 4, 5, 6, 7]
sorted(['cat', 'dog', 'cheetah', 'rhino', 'bear'], reverse=True)
# 輸出結果:['rhino', 'dog', 'cheetah', 'cat', 'bear']

值得了解的是可選關鍵字key,它允許你在排序之前指定將在每個元素上調用的函數。添加函數允許自定義排序規則,如果要對更復雜的數據類型進行排序,這些規則特別有用。

animals = [{'type': 'penguin', 'name': 'Stephanie', 'age': 8},
            {'type': 'elephant', 'name': 'Devon', 'age': 3},
             {'type': 'puma', 'name': 'Moe', 'age': 5},]

sorted(animals, key=lambda animal: animal['age'])

運行結果:
在這裏插入圖片描述

通過傳入一個返回每個元素年齡的lambda函數,可以輕鬆地按每個字典的單個值對字典列表進行排序。在這種情況下,字典現在按年齡按升序排序。

1.5 有效利用數據結構

選擇正確的數據結構會對性能產生重大影響。除了理論數據結構之外,Python還在其標準數據結構實現中內置了強大而方便的功能

  • 1:使用set存儲唯一值
    如果需要從現有數據集中刪除重複元素。新的開發人員有時會在列表應該使用集合時執行此操作,這會強制執行所有元素的唯一性。
import random
all_words = "all the words in the world".split()

def get_random_word(all_words):
    return random.choice(all_words)
get_random_word(all_words)

隨機選擇的結果:
在這裏插入圖片描述
應該重複調用get_random_word()以獲取1000個隨機單詞,然後返回包含每個唯一單詞的數據結構。以下是兩種常見的次優方法和一種好的方法。

# 糟糕的方法
def get_unique_words():
    words = []
    for i in range(1000):
        word = get_random_word()
        if word not in words:
            words.append(word)
    return words

這種方法很糟糕,因爲必須將每個新單詞與列表中已有的每個單詞進行比較。這意味着隨着單詞數量的增加,查找次數呈二次方式增長。換句話說,時間複雜度在O(N^2)的量級上增長。

換一種更好的方法

def get_unique_words():
    words = set()
    for i in range(1000):
        words.add(get_random_word())
    return words

那麼爲什麼使用與第二種方法不同的集合呢? 它們是不同的,因爲集合存儲元素的方式允許接近恆定時間檢查值是否在集合中,而不像需要線性時間查找的列表。查找時間的差異意味着添加到集合的時間複雜度以O(N)的速率增長,這在大多數情況下比第二種方法的O(N^2)好得多。

  • 2:使用生成器節省內存

前面提到,列表推導是方便的工具,但有時會導致不必要的內存使用。

比如:找到前1000個正方形的總和,從1開始

res = sum([i * i for i in range(1,1001)])
print(res)   # 輸出結果:333833500

很快將結果輸出,但是,這裏發生了什麼? 它正在列出你要求的每個完美的方塊,並將它們全部加起來。 具有1000個完美正方形的列表在計算機術語中可能不會很大,但是1億或10億是相當多的信息,並且很容易佔用計算機的可用內存資源。 有一種解決內存問題的快捷方法:只需用括號替換方括號。

sum((i * i for i in range(1, 1001))) 
# 輸出結果:333833500

生成器表達式並不真正的創建數字列表,而是返回一個生成器對象,此對象在每次計算出一個條目後,把這個條目"產生"(yield)出來。生成器表達式使用了"惰性計算"或稱作"延時求值"的機制。 序列過長,並且每次只需要獲取一個元素時,應該考慮生成器表達式而不是列表解析。
因此,當sum通過重複調用. next ()來迭代生成器對象時,生成器檢查i 等於多少,計算i * i,在內部遞增i,並將正確的值返回到sum。該設計允許生成器用於大量數據序列,因爲一次只有一個元素存在於內存中

  • 3:使用.get()和.setdefault()在字典中定義默認值
    最常見的編程任務之一涉及添加,修改或檢索可能在字典中或可能不在字典中的項。Python字典具有優雅的功能,可以使這些任務簡潔明瞭。
# 假設,我們要找出cowboy字典中的name字段對應的值
# 如果存在,則返回相應的值。否則,它返回默認值。
cowboy = {'age': 32, 'horse': 'mustang', 'hat_size': 'large'}
if 'name' in cowboy:
    name = cowboy['name']
else:
    name = 'The Man with No Name'
name

運行結果:
在這裏插入圖片描述

雖然上述方法可以清楚地檢查key確實有效,但如果使用.get(),它可以很容易地用一行代替
Python 字典(Dictionary) get() 函數返回指定鍵的值,如果值不在字典中返回默認值

name = cowboy.get('name','The Man with No Name')
name

輸出結果:
在這裏插入圖片描述

2 利用Python的標準庫

2.1 使用collections.defaultdict()處理缺少的字典鍵

假設你有一羣學生,你需要記錄他們在家庭作業上的成績。輸入值是具有格式(student_name,grade)的元組列表,但是你希望輕鬆查找單個學生的所有成績而無需迭代列表。

student_grades = {}
grades =  [('elliot', 91),
           ('neelam', 98),
           ('bianca', 81),
           ('elliot', 88),]

for name,grade in grades:
    if name not in student_grades:
        student_grades[name] = []
    student_grades[name].append(grade)
    
student_grades

輸出結果:
在這裏插入圖片描述
其實還有一個更簡潔的方法,可以使用defaultdict,它擴展了標準的dict功能,允許你設置一個默認值,如果key不存在,它將按默認值操作:

from collections import defaultdict

student_grades = defaultdict(list)
for name,grade in grades:
    student_grades[name].append(grade)
student_grades

在這裏插入圖片描述

2.2 使用collections.Counter計算Hashable對象

假如有一長串沒有標點符號或大寫字母的單詞,想要計算每個單詞出現的次數,可以使用字典或defaultdict增加計數,但collections.Counter提供了一種更清晰,更方便的方法。Counter是dict的子類,它使用0作爲任何缺失元素的默認值,並且更容易計算對象的出現次數:

# 當你將單詞列表傳遞給Counter時,它會存儲每個單詞以及該單詞在列表中出現的次數
from collections import Counter
words = "if there was there was but if there was not there was not".split()

counts = Counter(words)
counts

運行結果:
在這裏插入圖片描述

如果需要找出兩個最常見的詞是什麼,只需使用.most_common()

counts.most_common(2)

輸出結果:
在這裏插入圖片描述

2.3 使用字符串常量訪問公共字符串組

檢查字母是否都是大寫字母

import string
def is_upper(word):
    for letter in word:
        if letter not in string.ascii_uppercase:
            return False
    return True

print(is_upper('Thanks Sir'))
print(is_upper('LOL'))

運行結果:
在這裏插入圖片描述

2.4 使用Itertools生成排列和組合¶

對於排列,元素的順序很重要,因此(“sam”、“devon”)表示與(“devon”、“sam”)不同的配對,這意味着它們都將包含在列表中。

import itertools
friends = ['BeiJing', 'ShangHai', 'ChongQing', 'GuangZhou']
list(itertools.permutations(friends, r=2))

運行結果:
在這裏插入圖片描述

itertools.combinations()生成組合。這些也是輸入值的可能分組,但現在值的順序無關緊要。因爲(‘sam’、‘devon’)和(‘devon’、‘sam’)代表同一對,所以輸出列表中只會包含它們中的一個。

list(itertools.combinations(friends, r=2))

運行結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章