簡體   English   中英

如何在列表理解中做作業?

[英]How can I do assignments in a list comprehension?

我想在列表理解中使用賦值運算符。 我怎樣才能做到這一點?

以下代碼是無效語法。 我的意思是將lst[0]設置為空字符串''如果它匹配pattern

[ lst[0] = '' for pattern in start_pattern if lst[0] == pattern ]

謝謝!

Python 3.8 將引入賦值表達式

這是一個新符號: :=允許在(除其他外)推導式中賦值。 這個新的算子也被稱為海象算子

它將在計算/內存方面引入很多潛在的節省,從上面鏈接的 PEP 的以下片段中可以看出(適用於 SO 的格式):

語法和語義

在可以使用任意 Python 表達式的大多數上下文中,可以出現命名表達式。 這是NAME := expr的形式,其中expr是除無括號的元組之外的任何有效 Python 表達式,而NAME是標識符。

此類命名表達式的值與合並表達式的值相同,但附加的副作用是為目標分配了該值:

  1. 處理匹配的正則表達式

    if (match := pattern.search(data)) is not None: # Do something with match
  2. 無法使用 2-arg iter() 重寫的循環

    while chunk := file.read(8192): process(chunk)
  3. 重用計算成本高的值

    [y := f(x), y**2, y**3]
  4. 在理解過濾器子句及其輸出之間共享子表達式

    filtered_data = [y for x in data if (y := f(x)) is not None]

這在最近發布的 alpha 版本中已經可用(不推薦用於生產系統!)。 您可以在此處找到Python 3.8 的發布時間表

看起來您將列表理解與 Python 中的循環結構混淆了。

列表理解產生——一個列表! 它不適用於現有列表中的單個分配。 (雖然你可以折磨語法來做到這一點......)

雖然不太清楚您要從代碼中做什么,但我認為它更類似於循環列表(流控制)與生成列表(列表理解)

像這樣循環列表:

for pattern in patterns:
   if lst[0] == pattern: lst[0]=''

這是一種合理的方法,也是您在 C、Pascal 等中所做的。但是您也可以只測試列表中的一個值並更改它:

if lst[0] in patterns: lst[0] = ''

或者,如果您不知道索引:

i=lst.index[pattern]
lst[i]=''

或者,如果您有一個列表列表並且想要更改每個子列表的每個第一個元素:

for i, sublst in enumerate(lst):
    if sublst[i][0] in patterns: sublist[i][0]=''

等等等等等等

如果您想對列表的每個元素應用一些東西,那么您可以考慮使用列表推導式、映射或 Python 工具包中的許多其他工具之一。

就個人而言,我通常更傾向於使用列表推導式來創建列表:

 l=[[ x for x in range(5) ] for y in range(4)]  #init a list of lists...

哪個更自然:

l=[]
for i in range(4):
   l.append([])
   for j in range(5):
      l[i].append(j)      

但是要修改相同的列表列表,哪個更容易理解?

這:

l=[['new value' if j==0 else l[i][j] for j in range(len(l[i]))] for i in range(len(l))]

或這個:

for i,outter in enumerate(l):
    l[i][0]='new value'               

青年會

是一個很棒的教程。

Python 語言對表達式和語句有不同的概念。

賦值是一個語句,即使語法有時會讓你認為它是一個表達式(例如a=b=99可以工作,但它是一個特殊的語法情況,並不意味着b=99是一個表達式,例如在 C 中)。

列表推導式是表達式,因為它們返回一個值,從某種意義上說,它們執行的循環是一個事件,重點是返回的列表。

語句可以包含表達式,但表達式不能包含語句。

也就是說,列表項分配在內部轉換為方法調用(以允許創建類似列表的對象)並且方法調用是表達式。 因此,您可以在技術上在表達式中使用列表項分配:

[ lst.__setitem__(0, '') for pattern in start_pattern if lst[0] == pattern ]

然而,這被認為是不好的,因為它損害了可讀性,閱讀源代碼的難易程度是 Python 語言的主要關注點 例如,您應該改寫...

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''

順便說一句,感謝in運算符相當於更具可讀性

if lst[0] in start_pattern:
    lst[0] = ''

列表推導式用於它們的返回值,它們在內部創建一個循環......如果你想要的是循環,那么只需編寫一個循環......任何閱讀代碼試圖理解它所做的事情的人都會非常感激(和誰在幾周內包括你自己)。

簡而言之:你沒有。 列表推導用於生成列表,而不是修改現有列表。 如果要修改列表,請使用 for 循環,因為這就是它們的用途。

編寫該代碼的 Pythonic 方式類似於:

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''
        #the following assumes that pattern will never be ''
        #if that's possible, you can ignore this bit
        break

但是,如果您真的,真的想在一個內部進行賦值,並且不介意處理您的代碼的每個 Python 程序員永遠討厭它,那么您可以使用一些函數:

  • 如果要分配給的變量是全局變量,則可以執行

     globals().update(var=value)
  • 如果要分配給的變量是可變序列或映射(例如列表或字典)

     list.__setitem__(index, value)

正如上面的答案中提到的,在列表理解功能中不可能直接分配,但是有一種可行的方法可以使用exec方法來實現分配。

不僅僅是assignments我們可以在exec方法中傳遞任何 python 表達式來評估它。

在你的情況下,它可以通過

  [ exec(f"lst[0] = ''") for pattern in start_pattern if lst[0] == pattern ]

如果我們有一個對象列表,並且我們想在特定條件下為對象的特定屬性分配一個值,那么它可能是這樣的:

[ exec("p.age_status=child") for p in persons_obj_list if p.age <= 18 ]

注意:這將更改列表中現有對象的狀態,並且不會像在正常使用列表理解時返回的那樣返回對象列表。

如果你在問題中提到的是:

[ lst[0] = '' for lst in listOfLists if lst[0] == pattern ]

或模式列表

[ lst[0] = '' for lst in listOfLists if lst[0] in patterns ]

這實際上可以很容易地完成

[ [''] + lst[1:] for lst in listOfLists if lst[0] == pattern ]

或再次獲取模式列表

[[''] + lst[1:] for lst in listOfLists if lst[0] in patterns ]

也許這並不完全是您要尋找的,但我相信呈現這種情況是值得的。

假設您有一個字典list ,如下所示:

>>> fruits
[{'name': 'apple', 'quantity': 5}, {'name': 'banana', 'quantity': 4}]

使用正常的列表解析,您可能會找到您要查找的對象:

>>> [d for d in fruits if d['name'] == 'apple'] 
[{'name': 'apple', 'quantity': 5}]

因此,由於上面的if條件,您有一個包含單個元素的列表。

因此,您可以索引唯一的元素,訪問字典鍵之一並分配一個值:

>>> [d for d in fruits if d['name'] == 'apple'][0]['quantity'] += 1

結果如下:

>>> fruits
[{'name': 'apple', 'quantity': 6}, {'name': 'banana', 'quantity': 4}]

我可以建議您使用類而不是使用變量來分配值。 當您使用類時,您可以簡單地更改類值,然后返回結果。

我添加了一個我做過的例子:

def foo():
class result:
    def __init__(self):
        self.key = 0
        self.value = 0
        
    def change(self, key, value):
        self.key= key
        self.value= value
        return key

result_object= result()
class_result= [result_object.change(key, value) for key, value in temp_dict.items() if value > result_object.value][-1]
return class_result

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM