Python Forum
yield from - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: yield from (/thread-41989.html)



yield from - akbarza - Apr-19-2024

hi
in the below code, what is doing yield from? please explain:

#yield_from.py
# from:https://treyhunner.com/2018/04/keyword-arguments-in-python/


def join(*iterables, joiner):
    if not iterables:
        return
    yield from iterables[0]     #? yield from=?
    for iterable in iterables[1:]:
        yield joiner
        yield from iterable

'''That joiner variable doesn’t have a default value, so it must be specified:'''
list1=list(join([1, 2, 3], [4, 5], [6, 7], joiner=0))
print(list1)    # out: [1, 2, 3, 0, 4, 5, 0, 6, 7]
list2=list(join([1, 2, 3], [4, 5], [6, 7], joiner='-'))
print(list2)    #out: [1, 2, 3, '-', 4, 5, '-', 6, 7]
# the list(join([1, 2, 3], [4, 5], [6, 7])) causes erorr.with below message:
#TypeError: join() missing 1 required keyword-only argument: 'joiner'
thanks


RE: yield from - Larz60+ - Apr-19-2024

'join' don't use python class names for your function name, it will overload the original definition.
If at any future time you need the original definition of join, you will get the new definition instead.

The yield is a part of a generator and yields the current iteration value.
see: Generators

Example:
>>> def next_num():
...     numlist=[1,2,3,4,5,6,7,8]
...     for x in numlist:
...         yield x
... 
>>> for num in next_num():
...     print(num)
... 
1
2
3
4
5
6
7
8
>>>



RE: yield from - deanhystad - Apr-19-2024

yield from is for yielding values produced by another generator. Instead of this
for i in range(10):
    yield i
You can now do this:
yield range(10)
But this isn't just a shorthand way of writing a generator. The reasons for yield from are discribed in this pep

https://peps.python.org/pep-0380/


RE: yield from - snippsat - Apr-19-2024

def my_join(*iterables, my_joiner=None):
    if not iterables:
        return
    #yield from iterables[0]
    # The same as the loop under
    for item in iterables[0]:
         yield item
    for iterable in iterables[1:]:
        yield my_joiner
        yield from iterable

list1 = list(my_join([1, 2, 3], [4, 5], [6, 7], my_joiner=9999))
print(list1)
list2 = list(my_join([1, 2, 3], [4, 5], [6, 7], my_joiner='***'))
print(list2)
# Now i have made a default argument <None> so now dos this work
list3 = list(my_join([1, 2, 3], [4, 5], [6, 7]))
print(list3)
Output:
[1, 2, 3, 9999, 4, 5, 9999, 6, 7] [1, 2, 3, '***', 4, 5, '***', 6, 7] [1, 2, 3, None, 4, 5, None, 6, 7
yield from was new in Python 3.3.
As see in code i have comment it out,and write same code as a loop


RE: yield from - DeaD_EyE - Apr-19-2024

# removed the * in front of iterables
print("Definition of generator-function")


def join(iterables, joiner):
    print("First step of generator")
    # spliting iterable in first iterable and the rest
    first, *rest = iterables

    # yield each element from first
    yield from first
    # here the generator pauses until
    # next iteration

    print("Second step of generator")
    for iterable in rest:
        # yield joiner
        print("yield")
        yield joiner

        # yield each element from iterable from rest
        print("yield from")
        yield from iterable


# example
my_iterables = (
    range(3),
    range(4),
    range(2),
)
print("Calling generator-function")
gen = join(my_iterables, "-")
# generator
print("Generator:", gen)
print("Code inside the generator is not executed yet")
print("Iterating over generator with list(gen)")
print()
result = list(gen)  # <- this consumes the generator

# Now the generator is empy
print("Trying to consume gen again: ", list(gen))
print("But the generator is exhausted.")
print("Example with a for-loop")
print()
for element in join(my_iterables, "-"):
    print(element, type(element))