Reputation: 125
I want to have objects that have a method that returns a new element from an internal list each time it's called until it returned all of them (but itself is immutable).
While I could store e.g. index of the last looked element in the list, I want the object to be immutable, so that solution is out. I thought of using a generator here but I don't know how write it so that the method actually IS the generator, instead of returning one. And I want to access it from different places, not in one loop in one place, so I don't want a new generator each time.
I've tried that:
class Node:
def __init__(up, right, down, left):
self.up = up
self.right = right
self.down = down
self.left = left
def get_next_neighbour(self):
for neighbour in [self.up, self.right, self.down, self.left]:
if neighbour is not None:
yield neighbour
And I tried accessing it like that:
n = Node(1, 2, 3, 4)
next_neighbour = next(n.get_next_neighbour()) # returns 1
And then, in a completely different part of the code, but with the same object:
next_neighbour = next(n.get_next_neighbour()) # returns 1 again, while I want 2
I realise that get_next_neighbour()
returns a new generator each time, so that's why I always get 1. I'd just want get_next_neighbour()
itself to behave the actual generator that it returns. I hope I'm making sense here :\
Upvotes: 1
Views: 42
Reputation: 41177
This looks a bit like an XY Problem.
Instead of:
Initialization:
n = Node(1, 2, 3, 4)
Usage (in different parts of the code):
next_neighbour = next(n.get_next_neighbour())
, you could do:
Initialization:
n = Node(1, 2, 3, 4)
neighbours = n.get_next_neighbour()
Usage:
next_neighbour = next(neighbours)
Note:
I'm sure it's just a typo, but you should modify the initializer to:
def __init__(self, up, right, down, left): # self is missing
Upvotes: 2
Reputation: 169388
Each invocation of the function returns a new generator, sure. (The function still is the generator, but it just gets reinitialized on every call.)
If you really do want to share the state of the generator, you could split things like this, maybe, and store the generator in progress.
class Node:
def __init__(self, up, right, down, left):
self.up = up
self.right = right
self.down = down
self.left = left
self._neighbor_generator = None
def _get_next_neighbour(self):
print('Initialized new generator.')
for neighbour in [self.up, self.right, self.down, self.left]:
if neighbour is not None:
yield neighbour
self._neighbor_generator = None # next call will create a new generator
def get_next_neighbour(self):
if not self._neighbor_generator:
self._neighbor_generator = self._get_next_neighbour()
return self._neighbor_generator
n = Node(1, 2, 3, 4)
for x in range(10):
print(next(n.get_next_neighbour(), None))
outputs
Initialized new generator.
1
2
3
4
None
Initialized new generator.
1
2
3
4
None
Upvotes: 1