【问题标题】:overloading list comprehension mechanism in PythonPython中的重载列表理解机制
【发布时间】:2021-03-03 04:04:48
【问题描述】:

高级问题: 比如说,你创建了一个类,它的作用类似于一个列表,但可以快速搜索一个元素,即一个同时为其内容元素编制索引的列表,因此查找特定元素的索引是 O(1),而不是 O(n ),就像在标准列表中一样。那么接下来怎么做呢?

class Fast_List():
  def __init__(self):
    self._list = []
    self._index = {}

  def __getitem__(self, idx):
    return self._list[idx]

  def __call__(self, idx):
    return self._list[idx]

  def append(self, elem):
    idx = len(self._list)
    self._list.append(elem)
    self._index[elem] = idx

  def index(self, elem):
    return self._index[elem]

al = Fast_List()

al = [i**2 for i in range(1000)]

上述代码的最后一行将创建一个由连续整数平方组成的常规列表,而不是 Fast_list。
但如果我希望它返回理解语句的 Fast_List 版本怎么办 (当然,我在上面的课程中遗漏了一些函数定义,但它不应该影响我提出的问题

现在,当然,我知道我可以简单地使用 for 循环来构建我的 Fast_List

al = Fast_List()
for i in range(1000):
  al.append(i**2)

...但我喜欢理解机制,我想知道它是否可以用于创建用户定义的类对象

【问题讨论】:

  • 没有办法让列表推导不评估为列表。这就是构造的作用
  • @juanpa.arrivillaga 这是一个不计算为列表的列表推导:[1/x for x in range(666)]
  • @superbrain 在构建列表时遇到错误仍在构建列表。
  • @rdas 我同意“construct”但不同意“evaluate”。
  • @superbrain 也许“如果它没有错误地完成,总是评估一个列表”会更准确,但在这一点上这是分裂的头发。无论哪种方式,这对手头的讨论都没有帮助。

标签: python list overloading list-comprehension


【解决方案1】:

向您的Fast_List 添加一个备用构造函数,并在列表理解的结果上调用它。

class Fast_List():
  def __init__(self):
    self._list = []
    self._index = {}

  def __getitem__(self, idx):
    return self._list[idx]

  def __call__(self, idx):
    return self._list[idx]

  def append(self, elem):
    idx = len(self._list)
    self._list.append(elem)
    try:
      self._index[elem].append(idx)
    except KeyError:
      self._index[elem] = [idx]

  def index(self, elem):
    list_idx = self._index[elem]
    return list_idx

  @classmethod
  def from_list(cls, lst):
    self = cls()
    for el in lst:
      self.append(el)
    return self
result = Fast_List.from_list([i**2 for i in range(1000)])

现在您可能会说:“当然可以,但在将其提取到Fast_List 之前,我仍在构建列表,”这将是真的。但是,出于任何原因,您都不需要 这是一个列表。更改参数并使用 genexp 代替,突然之间您可以完全省略列表初始化。

  # inside Fast_List(), literally just a rename of from_list to from_iterable
  # and lst to iterable

  @classmethod
  def from_iterable(cls, iterable):
    self = cls()
    for el in iterable:
      self.append(el)
    return self

# and in the construction, literally just omit the square brackets
result = Fast_List.from_list(i**2 for i in range(1000))

事实上,您可能会注意到,您可以选择以这种方式初始化Fast_List!让我们这样做:

class Fast_List():
    def __init__(self, iterable=None):
        self._list = []
        self._index = {}
        if iterable is not None:
            for el in iterable:
                self.append(el)
    # the rest of the class is unchanged

result = Fast_List(i**2 for i in range(1000))

【讨论】:

  • 另外,__init__ 方法的可选参数可以是一个列表,将代码简化为 Fast_List([i**2 for i in range(1000)])
  • 我真的很感激这个答案,在我发布问题后很快就来了。但是您的解决方案仍然存在先创建常规列表然后将其转换为 Fast_List 的问题。有没有办法直接避免生成 Fast_List 所需的内存加倍? (好像Python中的所有东西都可以重载,那么重载理解机制怎么样?)
  • @ChrisWysocki 你读过我的全部答案了吗?我真的预料到了你的问题:)
  • 我们有答案。你们是最棒的!谢谢史密斯先生
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-15
  • 2021-04-20
  • 1970-01-01
  • 2018-06-24
  • 2018-02-06
  • 1970-01-01
相关资源
最近更新 更多