harry777
harry777

Reputation: 159

Python: passing argument to generator object created by generator expression?

so i have this gen object:

yld123cu = (x * u for x in range(1, 4))

which i can only use like so:

u = 2  # some user given value
for i in yld123cu:
    print(i, end=' ')

is there any syntax to avoid the extra line with u=.. assignment? any way to put the u value inside the for statement?

i'd want something similar to below but using gen expression, not function:

def yld123u(u):
    for i in range(1, 4):
        yield i * u

for i in yld123u(2):
    print(i, end=' ')

Upvotes: 9

Views: 14485

Answers (3)

Olivier Melançon
Olivier Melançon

Reputation: 22324

Since a generator expression cannot have its own scope, the preferred approach would be to define a generator function as you suggested.

def yld123u(u):
    for i in range(1, 4):
        yield i * u

If you need to update u along the way and this is the reason you want to avoid the above, then know that you can send a value to a generator.

def yld123u(u):
    for i in range(1, 4):
        received = yield i * u # a sent value will be assigned to 'received'
        u = u if received is None else received

Examples

The generator still behaves the same if you do not use send.

for x in yld123u(4):
    print(x)

Output

4
8
12 

You can use send to update the value of u.

gen = yld123u(4)
v0 = next(gen)
v1 = gen.send(0)
v2 = gen.send(4)
print(v0, v1, v2)

Output

4 0 12

Input loop

If you need the generator to interact with user input, here is a past answer of mine which suggest a way to implement a yield-receive generator usable in a for-loop.

class YieldReceive:
    stop_iteration = object()

    def __init__(self, gen):
        self.gen = gen
        self.next = next(gen, self.stop_iteration)

    def __iter__(self):
        return self

    def __next__(self):
        if self.next is self.stop_iteration:
            raise StopIteration
        else:
            return self.next

    def send(self, value):
        try:
            self.next = self.gen.send(value)
        except StopIteration:
            self.next = self.stop_iteration

Usage

it = YieldReceive(yld123u(4))
for x in it:
    print(x)
    it.send(int(input('Enter next u value: ')))

Upvotes: 18

hygull
hygull

Reputation: 8740

You can try like this.

Note: Here, we don't have a problem of using named lambda function.

for i in (lambda u: (x * u for x in range(1, 4)))(u=2): 
    print(i, end=' ')

or

for i in (lambda u: (x * u for x in range(1, 4)))(2): 
    print(i, end=' ')

» Output

2 4 6 

Upvotes: 1

Uli Sotschok
Uli Sotschok

Reputation: 1236

You can use lambda. This works for me:

yld123cu = lambda u: (x * u for x in range(1, 4))

for i in yld123cu(2):
    print(i, end=' ')

Upvotes: 2

Related Questions