[英]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
是标识符。此类命名表达式的值与合并表达式的值相同,但附加的副作用是为目标分配了该值:
处理匹配的正则表达式
if (match := pattern.search(data)) is not None: # Do something with match
无法使用 2-arg iter() 重写的循环
while chunk := file.read(8192): process(chunk)
重用计算成本高的值
[y := f(x), y**2, y**3]
在理解过滤器子句及其输出之间共享子表达式
filtered_data = [y for x in data if (y := f(x)) is not None]
这在最近发布的 alpha 版本中已经可用(不推荐用于生产系统!)。 您可以在此处找到Python 3.8 的发布时间表。
列表理解产生——一个列表! 它不适用于现有列表中的单个分配。 (虽然你可以折磨语法来做到这一点......)
虽然不太清楚您要从代码中做什么,但我认为它更类似于循环列表(流控制)与生成列表(列表理解)
像这样循环列表:
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.