简体   繁体   English

在 Python class 中用 __iter__ 方法实现递归 function

[英]Implementing recursive function with __iter__ method in a Python class

So I'm working on a problem in which I'm to create a Python Class to generate all Permutations of a list and I'm running across the following questions:所以我正在解决一个问题,我要创建一个 Python Class 来生成列表的所有排列,我遇到了以下问题:

  1. I can complete this easily with a simple recursive function, but as a class it seems like I would want to use the iter method.我可以使用简单的递归 function 轻松完成此操作,但作为 class 似乎我想使用iter方法。 My method calls a recursive function (list_all) that's almost identical to my iter , which is very unsettling.我的方法调用了一个递归的 function (list_all),它几乎与我的iter相同,这非常令人不安。 How do I modify my recursive function to be in compliance with best practices for iter ?如何修改我的递归 function 以符合iter的最佳实践?
  2. I wrote this code, saw that it worked, and I feel like I don't understand it, I try to trace the code line by line in a test case, but to me it looks like the first element in the list is frozen each time.我写了这段代码,看到它起作用了,但我觉得我不明白,我试着在测试用例中逐行跟踪代码,但对我来说,列表中的第一个元素似乎每个都被冻结了时间。 and the rest of the list is shuffled.并且列表的 rest 被洗牌。 Instead the output comes out in an unexpected order.相反,output 以意外的顺序出现。 I'm not understanding something!我有点不明白!

Thanks!谢谢!

class permutations():
  def __init__(self, ls):
    self.list = ls

  def __iter__(self):
    ls = self.list
    length = len(ls)
    if length <= 1:
      yield ls
    else:
      for p in self.list_all(ls[1:]):
        for x in range(length):
          yield p[:x] + ls[0:1] + p[x:]  

  def list_all(self, ls):
    length = len(ls)
    if length <= 1:
      yield ls
    else:
      for p in self.list_all(ls[1:]):
        for x in range(length):
          yield p[:x] + ls[0:1] + p[x:]

Just call self.list_all from __iter__ : 只需从__iter__调用self.list_all

class permutations():
  def __init__(self, ls):
    self.list = ls

  def __iter__(self):
    for item in self.list_all(self.list):
      yield item

  def list_all(self, ls):
    length = len(ls)
    if length <= 1:
      yield ls
    else:
      for p in self.list_all(ls[1:]):
        for x in range(length):
          yield p[:x] + ls[0:1] + p[x:]

Your list_all method is already a generator, so you can return that directly in __iter__ :您的list_all方法已经是一个生成器,因此您可以直接在__iter__中返回它:

class permutations():
    def __init__(self, ls):
        self.list = ls

    def __iter__(self):
        return self.list_all(self.list)

    def list_all(self, ls):
        length = len(ls)
        if length <= 1:
            yield ls
        else:
            for p in self.list_all(ls[1:]):
                for x in range(length):
                    yield p[:x] + ls[0:1] + p[x:]

This is both cleaner to read and executes faster.这既阅读起来更清晰,执行速度也更快。

You also have option is to define list_all inside __iter__ .您还可以选择在__iter__中定义list_all

class permutations2():
    def __init__(self, ls):
        self.list = ls

    def __iter__(self):
        def list_all(ls):
            length = len(ls)
            if length <= 1:
                yield ls
            else:
                for p in list_all(ls[1:]):
                    for x in range(length):
                        yield p[:x] + ls[0:1] + p[x:]
                    
        return list_all(self.list)

Timing permutations vs my permutations2 gives almost identical results.时序permutations与我的permutations2给出了几乎相同的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM