Python,应用于对象属性列表的映射函数
Python, map function applied to list of objects' attributes
出于任何实际原因,我有兴趣将 map 函数应用于对象列表,更具体地说,触发其中的方法。
考虑这个例子class:
class Something:
def __init__(self):
self.attr = 0
def step(self):
self.attr += 1
现在,使用 for 循环,我可以为列表中的每个对象迭代执行 step 方法并查看结果。
obj_list1 = [Something() for i in range(10)]
for elem in obj_list1:
elem.step()
[elem.attr for elem in obj_list1]
>>>
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
但是,如果我尝试使用 lambda 函数进行映射,事情就会出错:
obj_list2 = [Something() for i in range(10)]
list(map(lambda x: x.step(), obj_list2))
>>>
[None, None, None, None, None, None, None, None, None, None]
请注意,在最后一个代码片段中,我期待的是 Something 对象的列表,而不是 attr 属性。但是,None 在每个实例中都被 return 编辑了。
我的问题是:(A) 为什么要为每个元素编辑 None return?以及 (B) 应该如何以矢量化方式对一系列对象进行操作?
编辑:如回答所述,我在 step 方法中没有 return 值。可能有几种方法可以解决这个问题,其中一种方法本身不会改变 class,如下所示:
def trigger(obj):
obj.step()
return obj.attr
obj_list3 = [Something() for i in range(10)]
list(map(trigger, obj_list3))
>>>
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
None然而,map 是一种完全奇怪的以矢量化方式处理对象的方式吗?有更好的选择吗?等等
Edit2:在我最初的问题中,引用 obj_list2
,而 None
值的列表是 returned,当我调查列表中的属性时,所有这些都是增加到 1。有趣的发现!
您的函数步骤没有 return 值
def step(self):
self.attr += 1
所以将其映射到任何东西 returns 一个包含 None
的列表
在您的另一个示例中,您 return 编辑了 elem.attr
,这就是您得到不同结果的原因。
第二题,在
之后
obj_list3 = [Something() for i in range(10)]
list(map(trigger, obj_list3))
打印出 obj_list3
以查看每个对象是否已被映射尝试更改。
正在调用映射 step
,但您的步骤函数没有 return 语句,因此使用 None
的默认 return。
如果您希望地图以您所说的 Something 对象列表结尾,您可以 return self
从以下步骤开始:
def step(self):
self.attr += 1
return self # or perhaps return self.attr
尽管在这里使用 map 不一定是正确的,因为 map 的想法是将一个值的事物转换为另一个值,而您的 step
是在内部就地更改对象。
我认为 for 循环方式很好:
for elem in obj_list1:
elem.step()
出于任何实际原因,我有兴趣将 map 函数应用于对象列表,更具体地说,触发其中的方法。
考虑这个例子class:
class Something:
def __init__(self):
self.attr = 0
def step(self):
self.attr += 1
现在,使用 for 循环,我可以为列表中的每个对象迭代执行 step 方法并查看结果。
obj_list1 = [Something() for i in range(10)]
for elem in obj_list1:
elem.step()
[elem.attr for elem in obj_list1]
>>>
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
但是,如果我尝试使用 lambda 函数进行映射,事情就会出错:
obj_list2 = [Something() for i in range(10)]
list(map(lambda x: x.step(), obj_list2))
>>>
[None, None, None, None, None, None, None, None, None, None]
请注意,在最后一个代码片段中,我期待的是 Something 对象的列表,而不是 attr 属性。但是,None 在每个实例中都被 return 编辑了。
我的问题是:(A) 为什么要为每个元素编辑 None return?以及 (B) 应该如何以矢量化方式对一系列对象进行操作?
编辑:如回答所述,我在 step 方法中没有 return 值。可能有几种方法可以解决这个问题,其中一种方法本身不会改变 class,如下所示:
def trigger(obj):
obj.step()
return obj.attr
obj_list3 = [Something() for i in range(10)]
list(map(trigger, obj_list3))
>>>
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
None然而,map 是一种完全奇怪的以矢量化方式处理对象的方式吗?有更好的选择吗?等等
Edit2:在我最初的问题中,引用 obj_list2
,而 None
值的列表是 returned,当我调查列表中的属性时,所有这些都是增加到 1。有趣的发现!
您的函数步骤没有 return 值
def step(self):
self.attr += 1
所以将其映射到任何东西 returns 一个包含 None
在您的另一个示例中,您 return 编辑了 elem.attr
,这就是您得到不同结果的原因。
第二题,在
之后obj_list3 = [Something() for i in range(10)]
list(map(trigger, obj_list3))
打印出 obj_list3
以查看每个对象是否已被映射尝试更改。
正在调用映射 step
,但您的步骤函数没有 return 语句,因此使用 None
的默认 return。
如果您希望地图以您所说的 Something 对象列表结尾,您可以 return self
从以下步骤开始:
def step(self):
self.attr += 1
return self # or perhaps return self.attr
尽管在这里使用 map 不一定是正确的,因为 map 的想法是将一个值的事物转换为另一个值,而您的 step
是在内部就地更改对象。
我认为 for 循环方式很好:
for elem in obj_list1:
elem.step()