10

I want to pass a parameter to control the size of yielded data. For example,

class Something:
    def __init__(self):
        self.all_data = list(range(23))

    def __iter__(self, size):
        random.shuffle(self.all_data)
        batch = list()
        for i in self.all_data:
            batch.append(i)
            if len(batch) >= size:
                yield batch
                batch = list()

a = Something()
for i in a:  # TypeError: __iter__() missing 1 required positional argument: 'size'
    print(i)
for i in a(5):  # TypeError: 'Something' object is not callable
    print(i)
2
  • 1
    __iter__ must return an iterator, whatever you're doing should go in __next__ (without any additional parameter, take parameters when doing initialization and use those attributes). Commented Jan 28, 2019 at 5:25
  • @heemayl It is possible to pass in the size parameter during initialization. But this means that an instance can only set one size parameter. The yielded data size cannot be dynamically adjusted. Commented Jan 28, 2019 at 5:39

2 Answers 2

13

You can get your desirable effect by implementing __call__ method which will collect data for __iter__ to use, I set self.size in init constructor to ensure attribute existence.

It's not exactly what you want because it's not passing argument directly but via object's state, but it's working in case of for i in a(5)

please consider case when someone will use your code like this for i in a and by that, it can alter logic, you can check if self.size isn't None for example.

import random


class Something:
    def __init__(self):
        self.all_data = list(range(23))
        self.size = 0

    def __iter__(self):
        random.shuffle(self.all_data)
        batch = list()
        for i in self.all_data:
            batch.append(i)
            if len(batch) >= self.size:
                yield batch
                batch = list()

    def __call__(self, n):
        self.size = n
        return self


a = Something()

for i in a(0):
    print(i)
Sign up to request clarification or add additional context in comments.

2 Comments

The only problem with this is that for i in a doesn’t call the __call__() method.
But it makes sense right? If you don't use parenthesis ex. for i in a then it will use iter by default with whatever is self.size
0

i think it would be clearer to create a function that returns an iterator. or pass it in init

def __init__(self, data):
    #your code

for i in Something(42): pass

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.