I am brand-new to Python, and this is my first post on DaniWeb. Seems like a positive community, and I hope one day to contribute as a knowledgable expert and not a world-class newbie.

I'm wanting to create a simple python program that "fakes" Shakespeare or haiku-style output. I realize actual poems are more a matter of syllables, but I'm just getting my toes wet.

I want to create a program that can take an example.txt file of plain text and output its contents in either 10-word lines or in 7-5-7 word lines; the number of words in a line is arbitrary.

Dani AI

Generated

Good question from and a useful start from — a generator is the right mental model, but mutating a list with pop(0) can be slow for large inputs and easy to mis-handle at EOF. Below is a Python‑3 friendly pattern that keeps words in order, handles partial final lines gracefully, and avoids shifting a list repeatedly by using an iterator + itertools.islice.

from itertools import islice

def words_from_file(path, encoding='utf-8'):
    with open(path, encoding=encoding) as fh:
        for line in fh:
            for w in line.split():
                yield w

def lines_fixed(words_iter, n):
    it = iter(words_iter)
    while True:
        chunk = list(islice(it, n))
        if not chunk:
            break
        yield ' '.join(chunk)

def lines_pattern(words_iter, pattern):
    it = iter(words_iter)
    while True:
        stanza = []
        for n in pattern:
            chunk = list(islice(it, n))
            if not chunk:
                # output any partial stanza lines then finish
                for c in stanza:
                    yield ' '.join(c)
                return
            stanza.append(chunk)
        for c in stanza:
            yield ' '.join(c)
        # optional blank line between stanzas
        yield ''

Usage example:

it = words_from_file('example.txt')
for line in lines_pattern(it, (7, 5, 7)):
    print(line)

Practical notes:

  • For very large files, words_from_file streams lines so memory stays low.
  • .split() keeps punctuation attached to words; use a regex or a tokeniser if you need punctuation removed or special handling.
  • If you need true haiku (syllable-based), word counts are only an approximation; consider a syllable-counting library or dictionary lookup for accuracy.
  • Generators are single-use: to re-run, recreate the iterator (re-open the file or re-create the word generator).

This approach keeps the ordering strict, prints partial final lines instead of raising an IndexError, and is efficient for real texts.

Recommended Answers

All 7 Replies

You want random words or just re-splitting the lines with word count based line breaks?

Just re-splitting in the same order, based on the word count, yeah.

I would do something like this, don't be shy of starting to use yield to generate answers instead of making one time use lists without purpose.

bookfile = '11.txt'
pattern = (7, 5, 7)

def nwords(book, nwords):
    for dontcare in range(nwords):
        ## give word from begining (0) and remove from list of words one by one
        yield book.pop(0)
    ## finish giving words after nwords has been given 

with open(bookfile) as thebook:
    # read text of book and split from white space
    bookaslist =  thebook.read().split()
    # until bookaslist is empty, which is considered False value
    while bookaslist:
        for count in pattern:
            # rejoin count words and center it for 60 column print
            print ' '.join(nwords(bookaslist, count)).center(60)
        # empty line between to clarify the form
        print

Wow, great start and great response. I am getting errors, though (Python 3.1 is what I'm compiling in)
At first I was getting this error:

File "/Users/jonmitten/Documents/workspace/LyndaPython3EssentialTraining/poemizer.py", line 24
    print ' '.join(nwords(bookaslist, count)).center(60)
            ^
SyntaxError: invalid syntax

After adding parathesis to

print ' '.join(nwords(bookaslist, count)).center(60))

to

print( ' '.join(nwords(bookaslist, count)).center(60)))

I get this error:

Traceback (most recent call last):
  File "/Users/jonmitten/Documents/workspace/LyndaPython3EssentialTraining/poemizer.py", line 24, in <module>
    print( ' '.join(nwords(bookaslist, count)).center(60))
  File "/Users/jonmitten/Documents/workspace/LyndaPython3EssentialTraining/poemizer.py", line 14, in nwords
    yield book.pop(0)
IndexError: pop from empty list

Ok the yield should be:

from __future__ import print_function

bookfile = '11.txt'
pattern = (7, 5, 7)

def nwords(book, nwords):
    for dontcare in range(nwords):
        ## give word from begining (0) and remove from list of words one by one
        if book:
             yield book.pop(0)
        else:
             break
    ## finish giving words after nwords has been given 

with open(bookfile) as thebook:
    # read text of book and split from white space
    bookaslist =  thebook.read().split()
    # until bookaslist is empty, which is considered False value
    while bookaslist:
        for count in pattern:
            # rejoin count words and center it for 60 column print
            print(' '.join(nwords(bookaslist, count)).center(60))
        # empty line between to clarify the form
        print()

This means that it will return incorrect number of words from the end of the file, when the words finish at end of the file.

Wow, very cool. I'm going to have to look over the yield method to see what you did there.

Thanks for the decent head-start :)

Yield is handy, but you can get sometimes confused with it. Main headaches is, that sometimes you think you are putting values to list, but you put generator of values or you forget that once generated the values of generator are lost, and finally that after generator finishes, it is empty and you must recreate it to start again.

Here is one infinite generator of numbers up from starting value. It can not be used in for loop without exit statement, because it has not exit condition. After each yield the state of function is saved and the execution continues forward to next result.

def countup(x):
    while True:
        yield x
        x+=1

countfrom10= countup(10)
print(next(countfrom10))
print(next(countfrom10))
for i in range(10):
    print(next(countfrom10))

print(next(countfrom10))
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.