【问题标题】:Iterator to iterate over a generator迭代生成器的迭代器
【发布时间】:2018-05-16 09:21:40
【问题描述】:

我正在解析一个 XML 文件,其中一个 xml 标记的结构如下:

<product>
     <item seq="division-sec">Division</item>
     <item seq="dept-sec">Dept Info</item>
     <item seq="label01">Label 01</item>
     <item seq="label02">Label 02</item>
     ...
     <item seq="labelN">Label N</item>
     <item seq="date-mfg">27-11-2017</item>
     <item seq="date-exp">28-11-2019</item>
</product>  

我编写了一个生成器函数来按顺序访问产品标签:

def product_labels(xmlpage):
    #... parsed xml here
    for item in xmlpage:
       #-- process item for validation such as case sensitivity, etc
       yield item # ("division-sec", "Division")

现在我正在寻找一个函数,或者可能是一个迭代器类,它可以让我获得 first、last、prev、next 和 search 方法:

class ProdcutReader(object):
     def __init__(self, product_labels):
       self.product_labels = product_labels

     def __iter__(self):
        return self

     def __prev__(self):
        return prev(self.product_labels ) #-- Dont know how to do this :(

     def __next__(self):
        current = self.current(next(self.product_labels))
        return current

     def current(self, obj=None):
         if not obj:
            return self.first()
         return obj

     def first(self):
         return list(self.product_labels)[0]   

    # search by label seq 
    def search(self, seq):
       # Not sure if this is the correct way
       for i in self.product_labels:
           if i[0] == seq:
              self.current(i)
              return i
    ... # With some more methods (if search works I can have some more methods)

所以假设我需要使用那个对象,它应该像这样工作:

from product_reader import ProdcutReader as Reader
>>>r = Reader(product_labels)
>>>r.first()
("division-sec", "Division")
>>>r.last()
("date-exp", "28-11-2019")
>>>r.current()  # Let us say current is ("label01", "Label 01")
("label01", "Label 01")
>>>r.next() # or next(r)
("label02", "Label 02")
>>>r.prev()
("dept-sec", "Dept Info")
>>r.search("date-mfg") # This should also set the searched as r.current()  
("date-mfg", "27-11-2017")

如果我知道如何为 prev、next 和 search 编写方法,我将能够编写剩余的方法,例如 first、last、current 等。

【问题讨论】:

  • 发布一个测试用例,显示调用prev()nex()first()等方法时的预期结果
  • @RomanPerekhrest - 感谢您的建议,编辑了我的帖子。
  • 为什么def current(self, obj=None) 方法应该接受obj 参数?什么原因?
  • @RomanPerekhrest - 这是一个错字,已编辑!
  • 迭代器只前进。不支持第一个、最后一个或前一个元素,因为那样你就会有一个 sequence。迭代器是一次只在一个方向上移动的对一件事的序列的高效内存访问。

标签: python-3.x iterator


【解决方案1】:

你显然需要随时随机访问任何元素。在我看来,我不明白你为什么不简单地使用列表。

如果您需要当前/下一个/上一个功能而无需跟踪计数器变量,您仍然可以将您的构造基于列表:

class ProductReader(object):
    def __init__(self, product_labels):
        self.generator = product_labels
        self.active_generator = self.generator()
        self.element = None
        self.cur = -1

    def at_n(self, index):
        if self.cur > index:
            self.active_generator = self.generator()
        while len(self.storage) < index+1:
            self.element = next(self.active_generator)
        self.cur = index
        return self.element

    def current(self):
        if self.cur > -1:
            return self.element

    def last(self):
        try:
            while True:
                self.element = next(self.generator)
                self.cur += 1
        except StopIteration:
            return self.element

    def first(self):
        return self.at_n(0)

    def next(self):
        return self.at_n(self.cur+1)

    __next__ = next

    def prev(self):
        return self.at_n(self.cur-1)

    def search(self, query):
        oldcur = self.cur
        self.active_generator = self.generator()
        for i, element in enumerate(self.generator()):
            if query in element:
                self.cur = i
                self.element = element
                return element
        self.at_n(self.cur)  # reset to old state
        return None

【讨论】:

  • 感谢您的回复。因为我可以拥有一个 html 页面内容以及它的 css、图像、字体,这些内容是从每个产品的一个变量中的一个 zip 中提取的。所以不要把所有产品的数据放在列表中。我一次只想要一种产品。
  • 这意味着您每次想要返回、进行搜索等时都必须重新启动生成器。您确定这是您想要的吗?
  • (编辑了相同的评论)是的,我觉得这是目前唯一的方法。如果您对此有任何其他解决方案,请告诉我。
  • 编辑了我的答案以反映这一点,我认为这应该可行。
  • 这假设重新创建迭代器对象将再次产生相同的对象。这不是迭代器可以做出的保证。
猜你喜欢
  • 2018-05-24
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 2017-09-03
  • 2016-03-13
  • 1970-01-01
相关资源
最近更新 更多