1

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.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
Jacob Fuchs
  • 359
  • 1
  • 3
  • 14
  • 3
    for loops? list decomp? `print( *the_generator,sep="\n")` – Patrick Artner Jan 01 '19 at 16:30
  • @DavisHerring in that case .. more of a generator decomposition then list decomposition. See https://stackoverflow.com/questions/6319612/python-decompose-a-list - definitivly not a list comprehension. – Patrick Artner Jan 01 '19 at 16:35
  • 1
    @PatrickArtner: OK—that appears to be called [“unpacking”](https://docs.python.org/3/reference/expressions.html#calls), but I might say “expanding” to avoid the confusion with `a,b=f()` (which I sometimes in turn call “decomposition”). – Davis Herring Jan 01 '19 at 16:44

4 Answers4

2

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 
BlueSheepToken
  • 5,751
  • 3
  • 17
  • 42
Aman Raparia
  • 494
  • 1
  • 5
  • 13
1
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())
Bitto
  • 7,937
  • 1
  • 16
  • 38
1

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.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
0

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

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69