[Tutor] How to separate UI code from program logic?

boB Stepp robertvstepp at gmail.com
Mon May 7 01:26:08 EDT 2018

On Sun, May 6, 2018 at 5:05 PM, Alan Gauld <alan.gauld at yahoo.co.uk> wrote:
> On 6 May 2018, at 23:00, boB Stepp <robertvstepp at gmail.com> wrote:

>>My understanding of best practice here is that I should not have any
>>print() calls inside my generate_collatz_sequence() function.  I
>>_could_ store the generated sequence in a list and return it, but that
>>does not seem like good use of RAM if some user-supplied seed value
>>led to kazillions of Collatz sequence numbers being generated.
> The clue is in that last word.
> Write a generator function that yields the intermediate results.

Ok.  I've been reading up on generators and playing around with them
today.  And then, per Alan's hint, tried to separate all display code
from my program logic code.  What was originally meant to be a
throw-away effort, has somehow mushroomed into something I hope
resembles a finished product.  The results I came up with are as


#!/usr/bin/env python3

"""This program will generate a Collatz sequence from a user-supplied positive
integer.  According to Wikipedia

    "The Collatz conjecture is a conjecture in mathematics that concerns a
    sequence defined as follows: start with any positive integer n. Then each
    term is obtained from the previous term as follows: if the previous term is
    even, the next term is one half the previous term. Otherwise, the next term
    is 3 times the previous term plus 1. The conjecture is that no matter what
    value of n, the sequence will always reach 1."

def get_positive_integer():
    """Get a positive integer from the user."""

    while True:
            integer = int(input("Please enter a positive integer:  "))
            if integer > 0:
                return integer
                print("That was not a positive integer!")
        except ValueError:
            print("That was not an integer!")

def display_collatz_numbers(seed, collatz_generator):
    """Display a Collatz sequence, one value per line, given the seed (Which
    will be the first number in the sequence.) and a generator which will
    yield the Collatz sequence."""

    print("\nThe seed number: ", seed)
    for sequence_index, number in enumerate(collatz_generator):
        print("Sequence number", sequence_index + 1, ": ", number)

def ask_to_continue():
    choice = input("Do you wish to generate another Collatz sequence?").lower()
    return choice.startswith('y')

def get_collatz_number(integer):
    """Returns the Collatz sequence number corresponding to integer.  integer
    must be > 0, or the sequence will not converge to 1."""

    if integer % 2 == 0:
        return integer // 2
        return 3 * integer + 1

def generate_collatz_sequence(seed):
    """Creates a generator, which will yield a Collatz sequence starting from
    seed.  seed must be a positive integer, or the sequence will not converge to

    collatz_number = seed
    while True:
        collatz_number = get_collatz_number(collatz_number)
        yield collatz_number
        if collatz_number == 1:

def main():
    """Run program."""

    while True:
        seed = get_positive_integer()
        display_collatz_numbers(seed, generate_collatz_sequence(seed))
        if ask_to_continue():

if __name__ == '__main__':


Questions and comments:

1)  I am open to a general critique on making this code better.

2)  I spent a lot of effort trying to come up with a way to combine
the two functions, get_collatz_number() and
generate_collatz_sequence(), into something both more compact and more
readable, but I was unsuccessful.  I suspect there is a better way.
Is there?  And how would I do it?

3)  Is this the correct way to separate display code from program
logic code?  Is there a better way to do this?

4)  I think this is the first time I've actually tried to implement a
generator function.  Did I do a good Pythonic implementation of this?

As always, thanks!


More information about the Tutor mailing list