Text representation for numbers with python Simple function which returns a text representation for numbers in range [1...1000].

N100 = 'hundred'
N1000 = 'one thousand'
N1_9 = [
    'one', 'two', 'three',
    'four', 'five', 'six',
    'seven', 'eight', 'nine',
]
N10_19 = [
    'ten', 'eleven', 'twelve',
    'thirteen', 'fourteen', 'fifteen',
    'sixteen', 'seventeen', 'eighteen',
    'nineteen',
]
Nx10 = [
    'twenty', 'thirty', 'forty',
    'fifty', 'sixty', 'seventy',
    'eighty', 'ninety',
]


def make_word(num):
    assert 0 &lt; num &lt;= 1000
    if num == 1000:
        return N1000
    lst = [0] * 3
    for i in xrange(3):
        div = 10 ** (2 - i)
        lst[i] = num / div
        num %= div
    res = []
    if lst[0] != 0:
        res.append(
            '{} {}'.format(N1_9[lst[0]-1], N100)
        )
    if lst[1] or lst[2]:
        if lst[1] == 0:
            res.append(
                N1_9[lst[2] - 1]
            )
        elif lst[1] == 1:
            res.append(
                N10_19[lst[2]]
            )
        else:
            if lst[2] == 0:
                res.append(
                    Nx10[lst[1] - 2]
                )
            else:
                res.append(
                    '{}-{}'.format(Nx10[lst[1] - 2], N1_9[lst[2] - 1])
                )
    return ' and '.join(res)

for x in xrange(1, 1000 + 1):
     print x, make_word(x)


Is it possible to rewrite the function a little bit cleaner? Maybe decrease a number of branches somehow
rewrite the function a little bit cleaner


A way to achieve it, would be to divide your code into simpler functions, for instance:

lst = [0] * 3
for i in xrange(3):
    div = 10 ** (2 - i)
    lst[i] = num / div
    num %= div


Could be a simple function call:

lst = split_decimals(num)


(btw the name lst is not a very explicit...)


  Maybe decrease a number of branches somehow


To clean your branching, I would advise to make a function that treats one part of the problem: numbers between 1 and 99, with a function under_hundred_as_word for instance.

Better variable names might also help the reader to understand your code.



After some further refactoring, this is what I came with:

units = [
    'zero', 'one', 'two', 'three',
    'four', 'five', 'six',
    'seven', 'eight', 'nine',
]
tens = [
    '', '', 'twenty', 'thirty', 'forty',
    'fifty', 'sixty', 'seventy',
    'eighty', 'ninety',
]

hundred_exceptions = {
        10: 'ten',
        11: 'eleven',
        12: 'twelve',
        13: 'thirteen',
        15: 'fifteen',
        18: 'eighteen',
}

def under_hundred_as_word(num):
    assert 0 &lt; num &lt; 100

    unit = num % 10
    ten = num / 10
    if ten == 0:
        return units[unit]
    elif ten == 1:
        if num in hundred_exceptions:
            return hundred_exceptions[num]
        else:
            return units[unit] + 'teen'
    else:
        if unit:
            return tens[ten] + '-' + units[unit]
        else:
            return tens[ten]

def make_word(num):
    assert 0 &lt; num &lt;= 1000
    if num == 1000:
        return 'one thousand'

    parts = []

    # two last digits
    if num % 100:
        parts.insert(0, under_hundred_as_word(num % 100))

    # hundred digit
    hundreds = (num / 100) % 10
    if hundreds:
        hundreds = units[hundreds] + ' hundred'
        parts.insert(0, hundreds)

    return ' and '.join(parts)

for x in xrange(1, 1000 + 1):
    print x, make_word(x)


It can be easily modified to print numbers greater than 1000.