如何更新列表中所有数据类对象的属性?

3

我有一个以下类型对象的列表:

@dataclass
class Feature:
    name: str
    active: bool

我的列表是:

features = [Feature("name1",False), Feature("name2",False), Feature("name3",True)]

我想获取一个包含所有特征的列表,但将它们的 active 属性切换为 True。我尝试使用 map() 函数实现:

active_features=list(map(lambda f: f.active=True,features))

但是它给了我一个错误 expected parameter。如何实现呢?

注意:我以为它是从示例中得出的,但我想我应该澄清一下。我想用某种内联方法来做到这一点,而不是像一些答案建议的那样定义一个新的单独函数,但也许不能像这样做?


2
你想要一份新的实例清单,还是想要在原有实例中进行直接修改? - chepner
2
lambda 接受表达式而不是语句。赋值是一种语句,因此它无法工作。您不能真正使用列表推导,因为您的目标是更改状态而不是创建新列表。您想要一个具有其状态已切换的新对象列表,还是仅想要切换原始对象的状态? - Tomerikoo
@chepner 我无所谓,随你便。 - KZiovas
2
@KZiovas 你可能应该这样做。 - chepner
@chepner 为什么我会介意呢?我只是想在 pytest 中使用它。 - KZiovas
显示剩余2条评论
6个回答

5

您可以调用 dataclasses 的 replace 方法,它将创建一个带有更改属性的副本:

from dataclasses import dataclass, replace

@dataclass
class Feature:
    name: str
    active: bool
             
features = [Feature("used-to-be", False), Feature("maybe", False)]
active_features = [replace(x, active=True) for x in features]

print(active_features) # should be active
print(features) # should be intact

2

为什么你的逻辑不起作用?

它会给你错误,因为你正在使用的lambda函数试图修改f.active的值,这在lambda函数中是不允许的lambda函数只允许返回值的表达式,而不是执行某些操作的语句。

所以我认为可以像下面这样做-

from dataclasses import dataclass
import copy

@dataclass
class Feature:
    name: str
    active: bool


features = [Feature("name1",False), Feature("name2",False), Feature("name3",True)]
active_features = []
main_features = copy.deepcopy(features)
for f in main_features:
    f.active = True
    active_features.append(f)
print(active_features)
print(features) 

输出:

[Feature(name='name1', active=True), Feature(name='name2', active=True), Feature(name='name3', active=True)]

[Feature(name='name1', active=False), Feature(name='name2', active=False), Feature(name='name3', active=True)]

1

如果您愿意直接修改实例,而不需要构建新的列表,那么只需使用常规的 for 循环即可。

features = [Feature("name1",False), Feature("name2",False), Feature("name3",True)]

for f in features:
    f.active = True

如果您想要一个新的对象列表,而原来的对象保持不变,我建议仍然使用普通的for循环:
new_features = []
for f in features:
    new_features.append(Feature(f.name, True))

尽管添加一个实例方法,可以从现有的特征创建一个活动特征,这样做会使事情更加清晰:
@dataclass
class Feature:
    name: str
    active: bool

    def make_new_active(self):
        return type(self)(self.name, True)

features = [...]
new_features = [f.make_new_active() for f in features]

(请注意:我基本上是在重新实现dataclasses.replace,我忘记了这一点。请参见https://dev59.com/mMXsa4cB1Zd3GeqPn5_T#74852093。)

我喜欢后一种方法,我的唯一担忧是当属性列表开始扩展时,管理可能会失控。 - farbiondriven
喜欢您解决问题的想法,先生。 - A l w a y s S u n n y
1
这基本上就是你的答案;我只是忘记了 dataclasses.replace 的存在 :) - chepner

1
只需在原始类上创建一个方法。
@dataclass
class Feature:
    name: str
    active:bool
    def activate(self):
        self.active =True                                                 
        return self
                                                          
features = [Feature("name1",False), Feature("name2",False), Feature("name3",True)]

active_features=list(map(lambda f: f.activate(),features))                  

active_features

[Feature(name='name1', active=True), Feature(name='name2', active=True), Feature(name='name3', active=True)]

1

如果您想使用map来实现此操作,就不能使用lambda,因为lambda只能有表达式而不是赋值语句。而且它也必须返回某些内容。请改用以下方式:

from dataclasses import dataclass

@dataclass
class Feature:
    name: str
    active: bool
    
def activate_feature(feature: Feature):
        feature.active = True
        return feature


features = [Feature("name1",False), Feature("name2",False), Feature("name3",True)]

active_features = list(map(activate_feature, features))
print(active_features)

输出

[Feature(name='name1', active=True), Feature(name='name2', active=True), Feature(name='name3', active=True)]

如果您想使用Lambda,也可以这样做

from dataclasses import dataclass

@dataclass
class Feature:
    name: str
    active: bool
    
    def activate(self):
        self.active = True
        return self

features = [Feature("name1", False), Feature("name2", False), Feature("name3", True)]

active_features = list(map(lambda f: f.activate(), features))
print(active_features)

输出

[Feature(name='name1', active=True), Feature(name='name2', active=True), Feature(name='name3', active=True)]

0

更改旧列表中的数据:

from dataclasses import dataclass
from copy import deepcopy

@dataclass
class Feature:
    name: str
    active: bool

features = [Feature("name1",False), Feature("name2",False), Feature("name3",True)]

for feature in features:
    feature.active = True
print(features)
# [Feature(name='name1', active=True), Feature(name='name2', active=True), Feature(name='name3', active=True)]

或者创建一个包含修改后数值的新列表:

def func(feature):
    feature.active = True
    return feature
active_features = list(map(func, deepcopy(features)))

print(active_features)
# [Feature(name='name1', active=True), Feature(name='name2', active=True), Feature(name='name3', active=True)]

# If you try to print the original list, You can see that the element in the original does not change.

print(features)
# [Feature(name='name1', active=False), Feature(name='name2', active=False), Feature(name='name3', active=True)]

在 Lambda 函数中,你不能使用赋值运算符 =

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接