ylabel - python title position




列表理解與lambda+過濾器 (10)

Filter就是這樣。 它過濾出列表中的元素。 你可以看到定義中提到的相同(在我之前提到的官方文檔鏈接中)。 然而,列表理解是在處理先前列表中的某些事物之後產生新列表的事情 (過濾器和列表理解既創建新列表又不執行操作而不是舊列表)。比如說一個全新的數據類型,就像將整數轉換為字符串一樣)

在你的例子中,根據定義,最好使用過濾器而不是列表理解。 但是,如果你想要,從列表元素中說出other_attribute,在你的例子中是作為一個新列表來檢索的,那麼你可以使用列表理解。

return [item.other_attribute for item in my_list if item.attribute==value]

這就是我對濾波器和列表理解的記憶。 刪除列表中的一些內容並保持其他元素不變,使用過濾器。 在元素上使用自己的邏輯並創建適合某種用途的淡化列表,使用列表理解。

我偶然發現自己有一個基本的過濾需求:我有一個列表,我必須通過項目的屬性來過濾它。

我的代碼看起來像這樣:

my_list = [x for x in my_list if x.attribute == value]

但後來我想,寫這樣寫會不會更好?

my_list = filter(lambda x: x.attribute == value, my_list)

它更具可讀性,如果性能需要,lambda可以被拿出來獲得一些東西。

問題是:在使用第二種方式時是否存在任何警告? 任何性能差異? 我是否完全錯過了Pythonic Way™,應該用另一種方​​式來完成它(比如使用itemgetter而不是lambda)?


lambda版本的一個優點是,如果您的條件取決於它們,您可以捕獲其他變量:

value = 7
my_list = filter(lambda x, value=value: x.attribute == value, my_list)

因為

value = 7
my_list = [x for x in my_list if x.attribute == value]

將返回name 'value' is not defined因為變量值在條件中不可訪問。

兩種版本都可以在varaibale上進行檢查。


奇怪的是,不同的人有多少美女變化。 我發現列表理解比filter + lambda更清晰,但使用哪個更容易。 但是,請停止提供已經用於內置插件的變量名稱,這很令人困惑。

有兩件事可能會減慢你使用filter

首先是函數調用的開銷:只要你使用Python函數(無論是由def還是lambda創建的),過濾器可能比列表理解更慢。 這幾乎肯定不夠重要,除非你已經計算了代碼的時間,並且發現它是一個瓶頸,否則你不應該考慮性能問題,但差異將在那裡。

另一個可能適用的開銷是lambda被強制訪問一個範圍變量( value )。 這比訪問本地變量要慢,在Python 2.x中,列表理解只能訪問局部變量。 如果您使用的是Python 3.x,則列表理解將在單獨的函數中運行,因此它也將通過閉包訪問value ,並且此差異不適用。

要考慮的另一個選擇是使用生成器而不是列表理解:

def filterbyvalue(seq, value):
   for el in seq:
       if el.attribute==value: yield el

然後在你的主代碼中(這是可讀性真正重要的地方),你已經用一個希望有意義的函數名取代了列表理解和過濾器。


如果使用內置函數,通常filter會稍微快一點。

我希望你的情況下列表的理解速度會稍微快一點


我發現第二種方式更具可讀性。 它確切地告訴你意圖是什麼:過濾列表。
PS:不要使用'list'作為變量名稱


我的意思

def filter_list(list, key, value, limit=None):
    return [i for i in list if i[key] == value][:limit]

由於任何速度差異都是微乎其微的,無論是使用過濾器還是列表解析都可以歸結為品味。 總的來說,我傾向於使用理解(似乎與其他大多數答案一致),但有一種情況我更喜歡filter

一個非常頻繁的用例是將一些可迭代的X主體的值提取到謂詞P(x):

[x for x in X if P(x)]

但有時候你想首先將一些函數應用於值:

[f(x) for x in X if P(f(x))]


作為一個具體的例子,考慮

primes_cubed = [x*x*x for x in range(1000) if prime(x)]

我認為這看起來比使用filter好一點。 但現在考慮

prime_cubes = [x*x*x for x in range(1000) if prime(x*x*x)]

在這種情況下,我們希望根據事後計算的值進行filter 。 除了計算立方體兩次的問題(想像一個更昂貴的計算),還有兩次寫入表達式的問題,違反了DRY美學。 在這種情況下,我會很容易使用

prime_cubes = filter(prime, [x*x*x for x in range(1000)])

考慮到接受的答案,當你使用過濾器而不是列表理解時,我會給你一個角落案例。 你將有一天遇到列表不能被覆蓋的情況,這意味著你不能通過列表理解來直接處理它。 一個真實世界的例子是,如果您使用pyodbc從數據庫中讀取結果,則來自游標的fetchAll()結果是不可用的列表。 在這種情況下,要直接操作返回的結果,除了列表理解之外,過濾器是您的選擇。 例如:

cursor.execute("SELECT * FROM TABLE1;")
data_from_db = cursor.fetchall()
processed_data = filter(lambda s: 'abc' in s.field1 or s.StartTime >= start_date_time, data_from_db) 

如果你在這裡使用列表理解,你會得到錯誤:

TypeError:不可用類型:'list'


這是我在列表理解之後需要過濾某些東西時使用的一小段。 只是過濾器,拉姆達和列表的組合(或者稱為貓的忠誠度和狗的清潔度)。

在這種情況下,我正在閱讀一個文件,刪除空行,註釋掉行,以及在對一行進行評論之後的任何內容:

# Throw out blank lines and comments
with open('file.txt', 'r') as lines:        
    # From the inside out:
    #    [s.partition('#')[0].strip() for s in lines]... Throws out comments
    #   filter(lambda x: x!= '', [s.part... Filters out blank lines
    #  y for y in filter... Converts filter object to list
    file_contents = [y for y in filter(lambda x: x != '', [s.partition('#')[0].strip() for s in lines])]

雖然filter可能是“更快的方式”,但“Pythonic方式”不會關心這些事情,除非性能是絕對關鍵的(在這種情況下,您不會使用Python!)。







lambda