Python Forum

Full Version: Trying to access next element using Generator(yield) in a Class
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I have created a Class and used generator in a method which is supposed to yield even numbers between start and stop range. When trying to use next() of yield from the Class Obj, it is printing the same number. Is this not the right way to access?

# Creating Class Evem
class Even:
    # Constructor
    def __init__(self, start, stop, reverse=False):
        self.start = start
        self.stop = stop
        self.reverse = reverse
        # self.nums = []

    # Creating filter method using yeild/Generator
    def filter_even(self):
        for i in range(self.start, self.stop + 1):
            if i % 2 == 0:
                yield i


# Creating an Obj of class Even
even_nums = Even(10, 50, False)

# Making sure what's in the obj I have created
print(even_nums.__dict__)
# {'start': 10, 'stop': 50, 'reverse': False}


# Trying to print the yield result one by one
print(even_nums.filter_even().__next__())
print(even_nums.filter_even().__next__())
print(even_nums.filter_even().__next__())
print(even_nums.filter_even().__next__())

# Q: Why is printing the same element??
# 10
# 10
# 10
# 10
Am I not calling it the right way?
print(even_nums.filter_even().__next__())
Calling __next__ directly is not the best idea.

This line will call the function, which returns a generator.
The generator keeps the state. Then you're calling next on the generator, which yields the first result.
even_nums.filter_even().__next__()
But the generator is afterwards garbage collected because you have no reference to it.

  1. even_nums = Even(10, 50, False)
    for num in even_nums.filter_even():
        print(num)
        # only printing
  2. results = []
    even_nums = Even(10, 50, False)
    for num in even_nums.filter_even():
        print(num)
        results.append(num)
        # printing and appending to results
  3. even_nums = Even(10, 50, False)
    result = list(even_nums.filter_even())
  4. even_nums = Even(10, 50, False)
    result = tuple(even_nums.filter_even())
  5. even_nums = Even(10, 50, False)
    result = set(even_nums.filter_even())

You can also convert the class into an iterator iterable:
class Even:
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop

    def __iter__(self):
        for i in range(self.start, self.stop + 1):
            if i % 2 == 0:
                yield i


even_numbers = Even(10, 20)
result = list(even_numbers)
print(result)
This is a boring class. So if the only functionality is to filter out even numbers, you can turn it into a function/generator.


def filter_even_numbers(sequence):
        for number in sequence:
            if number % 2 == 0:
                yield number


numbers = [1,2,3,4,5,6]
result = list(filter_even_numbers(numbers))
If you need to select a start and stop index of your sequence, you can do it with the subscription:
numbers = [1,2,3,4,5,6]
numbers_to_process = numbers[1:]
# from index 1 to ...

result = list(filter_even_numbers(numbers_to_process))
(Oct-19-2020, 02:02 PM)DeaD_EyE Wrote: [ -> ]Calling __next__ directly is not the best idea.

This line will call the function, which returns a generator.
The generator keeps the state. Then you're calling next on the generator, which yields the first result.
even_nums.filter_even().__next__()
But the generator is afterwards garbage collected because you have no reference to it.

  1. even_nums = Even(10, 50, False)
    for num in even_nums.filter_even():
        print(num)
        # only printing
  2. results = []
    even_nums = Even(10, 50, False)
    for num in even_nums.filter_even():
        print(num)
        results.append(num)
        # printing and appending to results
  3. even_nums = Even(10, 50, False)
    result = list(even_nums.filter_even())
  4. even_nums = Even(10, 50, False)
    result = tuple(even_nums.filter_even())
  5. even_nums = Even(10, 50, False)
    result = set(even_nums.filter_even())

You can also convert the class into an iterator iterable:
class Even:
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop

    def __iter__(self):
        for i in range(self.start, self.stop + 1):
            if i % 2 == 0:
                yield i


even_numbers = Even(10, 20)
result = list(even_numbers)
print(result)
This is a boring class. So if the only functionality is to filter out even numbers, you can turn it into a function/generator.


def filter_even_numbers(sequence):
        for number in sequence:
            if number % 2 == 0:
                yield number


numbers = [1,2,3,4,5,6]
result = list(filter_even_numbers(numbers))
If you need to select a start and stop index of your sequence, you can do it with the subscription:
numbers = [1,2,3,4,5,6]
numbers_to_process = numbers[1:]
# from index 1 to ...

result = list(filter_even_numbers(numbers_to_process))

Thanks for your patience and explaining it very clearly.