为什么此 class 中的列表理解对某些方法有效,而对其他方法无效?
Why does list comprehension inside this class work for some methods and not for others?
我是一名研究科学家,正在编写自定义 class 我在 Python 3.7 中调用 MyList()
,旨在添加一些用于列表类型对象的额外方法。我希望这些方法能够就地修改列表对象,而不必重新定义它或将其分配给新的对象名称。例如,假设我已经声明了 foo = MyList()
并用一些任意数据填充了它。 我的目标是能够做这样的事情:
>>> foo
[1, 1, '', 3, [2, 4, '', 4, 5], [], [6] ]
>>> type(foo)
__main__.MyList
>>> foo.flatten_the_list()
>>> foo.remove_empty_items_from_list()
>>> foo.remove_duplicate_items_from_list()
>>> foo.convert_to_list_items_to_strings()
>>> foo
['1', '2', '3', '4', '5', '6']
我已经在下面发布了我的代码,到目前为止,一些方法工作正常。我集中精力从列表对象中删除空项,从列表对象中的项中删除空格,并将列表对象中的重复项删除到一个名为 MyList.cleanup()
的方法中,该方法运行良好。
但是,同样适用于 MyList.cleanup()
、的列表推导式用于展平列表,也不适用于将列表中每个项目的类型从整数转换为字符串。到目前为止我的代码:
class MyList(list):
# No def __init__() statement needed - inherits from list object
# MyList.convert_v2() WORKS without list comprehension
def convert_v2(self, dtype):
for i in range(len(self)):
self[i] = str(self[i])
return self
# MyList.convert_v1() DOESN'T WORK with list comprehension
def convert_v1(self, dtype):
self = [str(item) for item in self]
return self
# MyList.cleanup() WORKS with list comprehension
def cleanup(self):
# Remove empty items
self = [item for item in self if "" is not item]
# Remove duplicate items
self = list(dict.fromkeys(self))
# Remove whitespace (including \t and \n)
self = ["".join(str(item).split()) for item in self]
return self
# MyList.flatten() DOESN'T WORK with list comprehension
def flatten(self):
self = [item for sublist in self for item in sublist]
return self
这是我使用 MyList.convert_v1() 方法时得到的结果(我第一次尝试将列表内容转换为字符串的方法):
>>> bar
[1, 2, 3, 4, 5, 6]
>>> type(bar[0])
int
>>> bar.convert_v1()
['1', '2', '3', '4', '5', '6']
>>> bar
[1, 2, 3, 4, 5, 6]
>>> type(bar[0])
int
但是,我不得不停止使用列表推导来获得 MyList 的预期效果。convert_v2():
>>> bar
[1, 2, 3, 4, 5, 6]
>>> type(bar[0])
int
>>> bar.convert_v2()
['1', '2', '3', '4', '5', '6']
>>> bar
['1', '2', '3', '4', '5', '6']
>>> type(bar[0])
str
为什么MyList.convert_v2()
按预期工作,而MyList.convert_v1()
却没有?在 class 之外,我不希望这两个函数的行为有所不同,但在 class 内部,它们的行为确实不同。
类似地,这是我为 MyList.flatten() 方法得到的结果:
>>> baz
[[1, 2, 3, 4], [5, 6, 7, 8]]
>>> baz.flatten()
[1, 2, 3, 4, 5, 6, 7, 8]
>>> baz
[[1, 2, 3, 4], [5, 6, 7, 8]]
虽然所需的结果如图所示打印到输出,但列表对象 baz
实际上并未展平。调用方法后列表保持不变。我需要它来代替:
>>> baz
[[1, 2, 3, 4], [5, 6, 7, 8]]
>>> baz.flatten()
[1, 2, 3, 4, 5, 6, 7, 8]
>>> baz
[1, 2, 3, 4, 5, 6, 7, 8]
为什么列表理解在 MyList.cleanup()
方法中工作得很好,但在 MyList.convert()
中却不行或 MyList.flatten()
methods? 我知道我是 OOP 的新手,一般来说写 classes,所以如果我在这里完全偏离基地,我期待着了解我可以做些什么。
根据 @jasonharper 的评论,使用 self =
不会完成任何事情,因此要覆盖整个列表,只需使用 self[:]
.
为了展平列表,this answer 使用带递归的生成器,以便仍然可以展平未知深度的列表。
结合以上两者来完成您在第一个示例中想要的内容可能如下所示:
from collections.abc import Iterable
from re import sub
class MyList(list):
def _flattener(self, _list):
"""Generator used to flatten lists of undefined depth."""
for el in _list:
if isinstance(el, Iterable) and not isinstance(el, (str, bytes)):
yield from self._flattener(el)
else:
yield el
def flatten(self):
self[:] = self._flattener(self)
return self
def remove_empty(self):
self[:] = [item for item in self if item or item == 0]
return self
def convert_to_strings(self):
self[:] = list(map(str, self))
return self
def remove_duplicates(self):
self[:] = list(dict.fromkeys(self))
return self
def remove_whitespace(self):
self.convert_to_strings()
self[:] = [sub(r"\s+", "", item) for item in self]
return self
输出
>>> bar = MyList()
>>> bar.extend([0, 1, 1, "", 3, [2, 4, "", 4, 5], [], None, {}, [6], "Hello\n World"])
>>> bar.flatten()
>>> bar.remove_empty()
>>> bar.convert_to_strings()
>>> bar.remove_duplicates()
>>> bar.remove_whitespace()
>>> bar
['0', '1', '3', '2', '4', '5', '6', 'HelloWorld']
我是一名研究科学家,正在编写自定义 class 我在 Python 3.7 中调用 MyList()
,旨在添加一些用于列表类型对象的额外方法。我希望这些方法能够就地修改列表对象,而不必重新定义它或将其分配给新的对象名称。例如,假设我已经声明了 foo = MyList()
并用一些任意数据填充了它。 我的目标是能够做这样的事情:
>>> foo
[1, 1, '', 3, [2, 4, '', 4, 5], [], [6] ]
>>> type(foo)
__main__.MyList
>>> foo.flatten_the_list()
>>> foo.remove_empty_items_from_list()
>>> foo.remove_duplicate_items_from_list()
>>> foo.convert_to_list_items_to_strings()
>>> foo
['1', '2', '3', '4', '5', '6']
我已经在下面发布了我的代码,到目前为止,一些方法工作正常。我集中精力从列表对象中删除空项,从列表对象中的项中删除空格,并将列表对象中的重复项删除到一个名为 MyList.cleanup()
的方法中,该方法运行良好。
但是,同样适用于 MyList.cleanup()
、的列表推导式用于展平列表,也不适用于将列表中每个项目的类型从整数转换为字符串。到目前为止我的代码:
class MyList(list):
# No def __init__() statement needed - inherits from list object
# MyList.convert_v2() WORKS without list comprehension
def convert_v2(self, dtype):
for i in range(len(self)):
self[i] = str(self[i])
return self
# MyList.convert_v1() DOESN'T WORK with list comprehension
def convert_v1(self, dtype):
self = [str(item) for item in self]
return self
# MyList.cleanup() WORKS with list comprehension
def cleanup(self):
# Remove empty items
self = [item for item in self if "" is not item]
# Remove duplicate items
self = list(dict.fromkeys(self))
# Remove whitespace (including \t and \n)
self = ["".join(str(item).split()) for item in self]
return self
# MyList.flatten() DOESN'T WORK with list comprehension
def flatten(self):
self = [item for sublist in self for item in sublist]
return self
这是我使用 MyList.convert_v1() 方法时得到的结果(我第一次尝试将列表内容转换为字符串的方法):
>>> bar
[1, 2, 3, 4, 5, 6]
>>> type(bar[0])
int
>>> bar.convert_v1()
['1', '2', '3', '4', '5', '6']
>>> bar
[1, 2, 3, 4, 5, 6]
>>> type(bar[0])
int
但是,我不得不停止使用列表推导来获得 MyList 的预期效果。convert_v2():
>>> bar
[1, 2, 3, 4, 5, 6]
>>> type(bar[0])
int
>>> bar.convert_v2()
['1', '2', '3', '4', '5', '6']
>>> bar
['1', '2', '3', '4', '5', '6']
>>> type(bar[0])
str
为什么MyList.convert_v2()
按预期工作,而MyList.convert_v1()
却没有?在 class 之外,我不希望这两个函数的行为有所不同,但在 class 内部,它们的行为确实不同。
类似地,这是我为 MyList.flatten() 方法得到的结果:
>>> baz
[[1, 2, 3, 4], [5, 6, 7, 8]]
>>> baz.flatten()
[1, 2, 3, 4, 5, 6, 7, 8]
>>> baz
[[1, 2, 3, 4], [5, 6, 7, 8]]
虽然所需的结果如图所示打印到输出,但列表对象 baz
实际上并未展平。调用方法后列表保持不变。我需要它来代替:
>>> baz
[[1, 2, 3, 4], [5, 6, 7, 8]]
>>> baz.flatten()
[1, 2, 3, 4, 5, 6, 7, 8]
>>> baz
[1, 2, 3, 4, 5, 6, 7, 8]
为什么列表理解在 MyList.cleanup()
方法中工作得很好,但在 MyList.convert()
中却不行或 MyList.flatten()
methods? 我知道我是 OOP 的新手,一般来说写 classes,所以如果我在这里完全偏离基地,我期待着了解我可以做些什么。
根据 @jasonharper 的评论,使用 self =
不会完成任何事情,因此要覆盖整个列表,只需使用 self[:]
.
为了展平列表,this answer 使用带递归的生成器,以便仍然可以展平未知深度的列表。
结合以上两者来完成您在第一个示例中想要的内容可能如下所示:
from collections.abc import Iterable
from re import sub
class MyList(list):
def _flattener(self, _list):
"""Generator used to flatten lists of undefined depth."""
for el in _list:
if isinstance(el, Iterable) and not isinstance(el, (str, bytes)):
yield from self._flattener(el)
else:
yield el
def flatten(self):
self[:] = self._flattener(self)
return self
def remove_empty(self):
self[:] = [item for item in self if item or item == 0]
return self
def convert_to_strings(self):
self[:] = list(map(str, self))
return self
def remove_duplicates(self):
self[:] = list(dict.fromkeys(self))
return self
def remove_whitespace(self):
self.convert_to_strings()
self[:] = [sub(r"\s+", "", item) for item in self]
return self
输出
>>> bar = MyList()
>>> bar.extend([0, 1, 1, "", 3, [2, 4, "", 4, 5], [], None, {}, [6], "Hello\n World"])
>>> bar.flatten()
>>> bar.remove_empty()
>>> bar.convert_to_strings()
>>> bar.remove_duplicates()
>>> bar.remove_whitespace()
>>> bar
['0', '1', '3', '2', '4', '5', '6', 'HelloWorld']