为了账号安全,请及时绑定邮箱和手机立即绑定

在python迭代器中根据条件选择其他迭代器

在python迭代器中根据条件选择其他迭代器

不负相思意 2023-06-06 17:24:43
在 python 中,我有一个迭代器返回一个固定范围内的无限索引字符串,[0, N]称为Sampler. 实际上我有一个列表,它们所做的只是返回范围内的索引[0, N_0], [N_0, N_1], ..., [N_{n-1}, N_n].我现在要做的是首先根据范围的长度选择这些迭代器中的一个,所以我有一个weights列表[N_0, N_1 - N_0, ...],我选择其中一个:    iterator_idx = random.choices(range(len(weights)), weights=weights/weights.sum())[0]接下来,我想要做的是创建一个迭代器,它随机选择一个迭代器并选择一批M样本。class BatchSampler:    def __init__(self, M):        self.M = M        self.weights = [weight_list]        self.samplers = [list_of_iterators]        ]        self._batch_samplers = [            self.batch_sampler(sampler) for sampler in self.samplers        ]    def batch_sampler(self, sampler):        batch = []        for batch_idx in sampler:            batch.append(batch_idx)            if len(batch) == self.M:                yield batch        if len(batch) > 0:            yield batch    def __iter__(self):        # First select one of the datasets.        iterator_idx = random.choices(            range(len(self.weights)), weights=self.weights / self.weights.sum()        )[0]        return self._batch_samplers[iterator_idx]问题在于它似乎iter()只被调用一次,所以只iterator_idx选择了第一次。显然这是错误的......解决这个问题的方法是什么?当您在 pytorch 中有多个数据集时,可能会出现这种情况,但您只想从其中一个数据集中采样批次。
查看完整描述

1 回答

?
ibeautiful

TA贡献1993条经验 获得超5个赞

在我看来,您想定义自己的容器类型。
我尝试提供一些标准方法的示例
(希望不会遗漏太多细节);
您应该能够将这些简单示例之一重用
到您自己的课程中。


仅使用 __getitem__ (支持索引和循环):

对象.__getitem__

被调用以执行对自我[key]的评估。

class MyContainer:

  def __init__(self, sequence):

    self.elements = sequence  # Just something to work with.

  

  def __getitem__(self, key):

    # If we're delegating to sequences like built-in list, 

    # invalid indices are handled automatically by them 

    # (throwing IndexError, as per the documentation).

    return self.elements[key]


t = (1, 2, 'a', 'b')

c = MyContainer(t)

elems = [e for e in c]

assert elems == [1, 2, 'a', 'b']

assert c[1:-1] == t[1:-1] == (2, 'a')

使用迭代器协议:

对象.__iter__

object.__iter__(self)
当容器需要迭代器时调用此方法。此方法应返回一个新的迭代器对象,该对象可以迭代容器中的所有对象。对于映射,它应该遍历容器的键。
迭代器对象也需要实现这个方法;他们必须自己返回。有关迭代器对象的更多信息,请参阅迭代器类型。

迭代器类型

container.__iter__()
返回一个迭代器对象。该对象需要支持下面描述的迭代器协议。

迭代器对象本身需要支持以下两种方法,它们共同构成了迭代器协议:

iterator.__iter__()
返回迭代器对象本身。这是允许容器和迭代器与 for 和 in 语句一起使用所必需的。

iterator.__next__()
从容器中返回下一个项目。如果没有其他项目,则引发 StopIteration 异常。

一旦迭代器的 __next__() 方法引发 StopIteration,它必须在后续调用中继续这样做。


class MyContainer:

  class Iter:

    def __init__(self, container):

      self.cont = container

      self.pos = 0

      self.len = len(container.elements)

    

    def __iter__(self): return self

    def __next__(self):

      if self.pos == self.len: raise StopIteration

      curElem = self.cont.elements[self.pos]

      self.pos += 1

      return curElem

  

  def __init__(self, sequence):

    self.elements = sequence  # Just something to work with.

  

  def __iter__(self):

    return MyContainer.Iter(self)


t = (1, 2, 'a', 'b')

c = MyContainer(t)

elems = [e for e in c]

assert elems == [1, 2, 'a', 'b']

使用发电机:

发电机类型

Python 的生成器提供了一种实现迭代器协议的便捷方式。如果一个容器对象的iter () 方法被实现为一个生成器,它将自动返回一个迭代器对象(技术上,一个生成器对象)提供 iter ( ) 和next () 方法。

发电机

返回生成器迭代器的函数。它看起来像一个普通函数,只是它包含 yield 表达式,用于生成一系列可在 for 循环中使用的值,或者可以使用 next() 函数一次检索一个值。
通常指代生成器函数,但在某些情况下可能指代生成器迭代器。

生成器迭代器

由生成器函数创建的对象。

6.2.9. 产量表达式

在函数体中使用 yield 表达式会使该函数成为生成器


class MyContainer:

  def __init__(self, sequence):

    self.elements = sequence  # Just something to work with.

  

  def __iter__(self):

    for e in self.elements: yield e


t = (1, 2, 'a', 'b')

c = MyContainer(t)

elems = [e for e in c]

assert elems == [1, 2, 'a', 'b']


查看完整回答
反对 回复 2023-06-06
  • 1 回答
  • 0 关注
  • 108 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信