-2

I am trying to emulate the "chain" function in itertools in python.

I came up with the following generator.

# Chain make an iterator that returns elements from the first iterable
# until it is exhausted, then proceeds to the next iterable, until all
# of the iterables are exhausted.
def chain_for(*a) :
    if a :
       for i in a :
          for j in i :
             yield j
    else :
       pass    

How can I emulate the same function in a class? Since the input to the function is an arbitrary number of lists, I am not sure if packing/unpacking can be used in classes, and if so I am not sure how to unpack in the 'init' method.

class chain_for :
   def __init__(self, ...) :
      ....
   def __iter__(self) :
      self
   def __next__(self) :
      .....

Thank you.

Farrousa
  • 149
  • 1
  • 11

1 Answers1

1

There is not (much) difference between def chain_for(*a): and def __init__(self, *a):. Hence, a very crude way to implement this can be:

class chain_for:
    def __init__(self, *lists):
        self.lists = iter(lists)
        self.c = iter(next(self.lists))

    def __iter__(self):
        while True:
            try:
                yield next(self.c)
            except StopIteration:
                try:
                    self.c = iter(next(self.lists))
                except StopIteration:
                    break
                yield next(self.c)

chain = chain_for([1, 2], [3], [4, 5, 6])
print(list(chain))

Outputs:

[1, 2, 3, 4, 5, 6]
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
  • I see three major flaws here. First, this fails to be either an iterator or a reusable iterable. [Second, it breaks if any of the inputs are empty.](https://ideone.com/2ZksOS) Third, using `yield` defeats what little point there is in writing a class - almost the only reason to write a class for this kind of thing is as a learning exercise in how to manage iterator state manually. – user2357112 Oct 27 '19 at 12:57
  • 1
    @user2357112 `"almost the only reason to write a class for this kind of thing is as a learning exercise in how to manage iterator state manually"` Which is obviously the premise of this question, otherwise why would anyone attempt to re-implement a well tested stdlib code. The other 2 points of your comment are exactly why I used the phrase "a very crude way" in my answer – DeepSpace Oct 27 '19 at 12:59
  • Then why did you use `yield`? – user2357112 Oct 27 '19 at 13:01
  • 2
    @user2357112 because I felt like? why does it matter? You are welcome to post an answer which does not use `yield`. I've never said using `yield` was the only/most correct way to answer this question. – DeepSpace Oct 27 '19 at 13:02
  • If you're using `yield`, you're *not* managing iterator state manually. You're letting the generator suspension mechanism do it for you. This defeats what you just said was obviously the point of the question. – user2357112 Oct 27 '19 at 13:03
  • Thanks again, @DeepSpace for providing the solution. – Farrousa Oct 27 '19 at 13:09