python - 为什么此类中的列表理解对某些方法有效,而对其他方法无效?

标签 python class oop methods list-comprehension

我是一名研究科学家,正在 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 和编写类总体来说是新手,所以如果我在这里完全偏离了基地,我期待着了解我可以做些什么不同的事情。

最佳答案

根据 @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']

关于python - 为什么此类中的列表理解对某些方法有效,而对其他方法无效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68688377/

相关文章:

python - 自定义 View 在带有 Elastic Search 的 Django Haystack 中不显示结果

java - 比较来自不同类的 2 个实例的公共(public)字段

Python3 名称错误 : name 'method' is not defined for defined @staticmethod

java - 如何检查元素是否是类列表中元素的子类

oop - MATLAB 类的 Description 和 DetailedDescription 属性

python - 是否可以在不使用 exec、eval、compile 的情况下从函数内删除外部对象引用(变量)?

python - 使用 python twisted 编写网络爬虫

python - 类型错误 : unsupported operand type(s) for +: 'float' and 'tuple'

c++ - 创建新类的开销

c++ - 在 using 语句中指定类名有什么作用?