【发布时间】:2021-10-11 17:58:51
【问题描述】:
我是一名研究科学家,我在 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() 却没有?在类之外,我不希望任何一个函数的行为不同,但在类内部它们的行为确实不同。
在类似的注释中,这是我从 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() 方法?我认识到我是 OOP 和一般编写类的新手,所以如果我完全不了解这里,我期待了解我可以做哪些不同的事情。
【问题讨论】:
-
您想修改现有列表还是创建一个新列表?因为你的函数在不同的时间做这两件事。如果你想创建一个新列表,你想确保它是另一个
MyList,还是一个普通的list好吗? -
@SilvioMayolo 我想修改现有列表,并且我想确保它仍然是 MyList,以便我可以使用这些以及任何其他方法继续前进。
-
self只是你方法中的一个局部变量。为它分配一个新值是完全没有意义的,这在方法之外没有任何影响。要更改实例的基础列表值,您必须分配给self的元素或切片;例如,self[:] = [...whatever...]将完全替换现有内容。 -
如果你想处理任意嵌套深度,你的 flatten 方法需要递归。就像现在一样,它只会处理其成员是 all 平面子列表的列表。它将在
[1, 2]、[1, [2, 3]]或[[[1, 2], [3, 4]], [4, 5]]上失败。 -
我建议把你的类写成一个列表的包装器,而不是从一个列表继承。如果您希望它具有大部分相同的功能,您可以委托给 __getattr__。正如 jasonharper 所说,当您使用 self = 时,它只不过是一个非常令人困惑的变量名。
标签: python class oop methods list-comprehension