Jacob Fuchs
Jacob Fuchs

Reputation: 357

Printing all results from a Python generator

I have made a generator function which search a csv file using a keyword and I want to print the results if there is something. How can I do that without using the print(next(gen_results)) over and over again?

I have tried a try-catch statement for the stopIteration, when there is no matching of keyword with a contact but I want a more concise solution.

def search(keyword, filename):
    f = open(filename, 'r')
    for line in f:
        if keyword in line:
            yield line
    f.close()

the_generator = search('Python', 'contacts.csv')
print(next(the_generator))
print(next(the_generator))  

contacts.csv
Name01, 89888
Name02, 8885445
Name03, 54555
Name04, 55544584
Name05, 55855
Python, 100
BigPi, 444
Python, 101

I expect the output to be a statement as 'Nothing Found',if there are no contacts with the keyword. In case there are contacts with the keyword, it outputs all the listings.

Upvotes: 1

Views: 1294

Answers (4)

Aman Raparia
Aman Raparia

Reputation: 491

Please try this

def search(keyword, filename):
    f = open(filename, 'r')
    for line in f:
        if keyword in line:
            yield line
        else:
            yield 'Nothing Found'
    f.close()

the_generator = search('Python', 'contacts.csv')
for g in the_generator:
    print(g)

'the_generator' is an iterate object and 'for' loop needs an iterate object to run. The output of the program will :

Nothing Found
Nothing Found
Nothing Found
Nothing Found
Nothing Found
Python, 100 

Upvotes: 2

hpaulj
hpaulj

Reputation: 231385

You could put the 'not found' test in the generator itself:

def search(keyword, lines):
    cnt = 0
    for line in lines:
        if keyword in line:
            cnt += 1
            yield line
    if cnt==0:
        yield "NOT FOUND"

In [166]: txt = """Name01, 89888
     ...: Name02, 8885445
     ...: Name03, 54555
     ...: Name04, 55544584
     ...: Name05, 55855
     ...: Python, 100
     ...: BigPi, 444
     ...: Python, 101
     ...: """.splitlines()
In [167]: for x in search("Python",txt):print(x)
Python, 100
Python, 101
In [168]: for x in search("Foobar",txt):print(x)
NOT FOUND

Otherwise I think the simplest is to list the generator, and check for an empty list. By itself the generator mechanism does not count the number of yields.

Upvotes: 1

Bitto
Bitto

Reputation: 8215

def search(keyword, filename):
    f = open(filename, 'r')
    for line in f:
        if keyword in line:
            yield line
    f.close()

the_generator = search('Python', 'contacts.csv')
my_list=list(the_generator)
if not my_list:
    print("Not Found")
for item in my_list:
    print(item.strip())

Upvotes: 1

Patrick Artner
Patrick Artner

Reputation: 51643

There are several methods to consume the generator - unsing next() only consumes (the next) value of it.

Generate file:

def gen_file():
    with open("contacts.csv","w") as f:
        f.write("""Name01, 89888
Name02, 8885445
Name03, 54555
Name04, 55544584
Name05, 55855
Python, 100
BigPi, 444
Python, 101
""")

Use it:

gen_file()   

def search(keyword, filename="contacts.csv"):
    """Changed to use .. with open() as f: ... style syntax."""
    with open(filename, 'r') as f:
        for line in f:
            if keyword in line:
                yield line 


# consume all of it into a list - you can reuse it
print("-"*40)
the_generator = search('Python', 'contacts.csv')
contacts = list(the_generator)
print(*contacts, sep="")


print("-"*40)
# decompose the generator directly for printing
the_generator = search('Python', 'contacts.csv')
print(*the_generator, sep="" ) 


print("-"*40)
# use a for loop over the generated results
the_generator = search('Python', 'contacts.csv')
for li in the_generator:
    print(li, end="") # remove end=\n


print("-"*40)
# using str.join to create the output
the_generator = search('Python', 'contacts.csv')
print("".join(the_generator))


print("-"*40)
# loop endlessly until StopIteration is raised
try:
    while True:
        print(next(the_generator), end="")
except StopIteration:
    pass

etc.

Output (several times):

----------------------------------------
Python, 100
Python, 101

The "best" one if you do not reuse the generated values is probably print(*the_generator,sep="") or the more explicit:

# use a for loop over the generated results
the_generator = search('Python', 'contacts.csv')
for li in the_generator:
    print(li,end="") # remove end=\n

You may also want to read here: Using yield from with conditional in python

Upvotes: 0

Related Questions