chewflow
chewflow

Reputation: 81

Why is python returning an empty list when I explicitly ask it not to?

apologies in advance - I'm new to coding so this is probably a silly question!

I'm trying to scan a local text file (I downloaded the text from http://norvig.com/big.txt) and then read and print random lines from this file into a list.

However, I don't want to print any empty lines, just the lines that contain text.

So I've tried to use the following code:

import random

with open('C:\\big.txt', 'r') as f:
    while True:
        random_line_str = random.choice(f.readlines())
        random_line_lst = random_line_str.split()
        if random_line_lst != []:
            print(random_line_lst)
            break

So this works fine for lines that contain text. But it also occasionally spits out the following error:

Traceback (most recent call last):
  File "C:\Python\lib\random.py", line 253, in choice
    i = self._randbelow(len(seq))
  File "C:\Python\lib\random.py", line 230, in _randbelow
    r = getrandbits(k)          # 0 <= r < 2**k
ValueError: number of bits must be greater than zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/PycharmProjects/Testing/Test.py", line 5, in <module>
    random_line_str = random.choice(f.readlines())
  File "C:\Python\lib\random.py", line 255, in choice
    raise IndexError('Cannot choose from an empty sequence')
IndexError: Cannot choose from an empty sequence

I haven't got a clue what's going on here to be honest...

Any ideas how I can avoid this happening and only return lines that contain text?

Cheers!

Upvotes: 0

Views: 1715

Answers (3)

Strik3r
Strik3r

Reputation: 1057

I feel you can make use of strip method in this situation, because even if the line is empty you will still have the carriage return associated to that line. So you can check for the following condition

line.strip() != '' #checking if the line is empty by removing the Carriage return 

with open('fdf.txt','r') as f:
     for line in f:
        if line.strip() != '' :
            print(line)

Hope it helps.

Upvotes: 2

taskinoor
taskinoor

Reputation: 46027

print out if random_line_lst is not []

No, you are not checking for that. Rather you are checking whether list variable random_line_lst do not exists in [] which is always true since [] is empty and nothing exists in it. So if random_line_lst not in []: check is not correct.

Instead of you need to check:

if len(random_line_lst) > 0:

Or a short-cut (and better form) is to check

if random_line_lst:

Since empty lists are false.

Also, you can't call f.readlines() always inside loop. You need to keep that lines in a variable before the loop starts, otherwise you will get an IndexError next time the loop runs. The reason is in the first call of f.readlines() the whole file is read, and in next call file position is already at end of file, so next read will return empty list, unless you seek to zero position of the file. For your case you can just move the readlines() call out of loop.

with open('C:\\big.txt', 'r') as f:
    lines = f.readlines()
    while True:
        random_line_str = random.choice(lines)

Upvotes: 2

Alex Huszagh
Alex Huszagh

Reputation: 14614

This line doesn't check if the item is an empty list, it checks if the item is in an empty list, which will always be false (meaning item not in [] will always be true):

if random_line_lst not in []:

What you can do is since bool([]) is False, just do:

if random_line_lst:

If you would likely to explicitly check for an empty list, use the != operator.

if random_line_lst != []:

Using the above, your code then becomes:

import random

with open('C:\\big.txt', 'r') as f:
    while True:
        random_line_str = random.choice(f.readlines())
        random_line_lst = random_line_str.split()
        if random_line_lst:
            print(random_line_lst)
            break

EDIT

For the random.choice, the issue is you are repeatedly calling random.choice on f.readlines(). Readlines only returns each line on the first call, afterwards it will just return an empty sequence. random.choice cannot select an item from an empty sequence. A better strategy is this:

import random

with open('C:\\big.txt', 'r') as f:
    lines = f.readlines()
    while True:
        random_line_str = random.choice(lines)
        random_line_lst = random_line_str.split()
        if random_line_lst:
            print(random_line_lst)
            break

Or, if you can break away from randomness, use the following:

with open('C:\\big.txt', 'r') as f:
    for line in f:
        line_lst = line.split()
        if line_lst:
            print(line_lst)
            break

Upvotes: 3

Related Questions