Home > Articles

  • Print
  • + Share This
This chapter is from the book

4.2 Twenty-Two Programming Shortcuts

This section lists the most common techniques for shortening and tightening your Python code. Most of these are new in the book, although a few of them have been introduced before and are presented in greater depth here.

  • Use Python line continuation as needed.

  • Use for loops intelligently.

  • Understand combined operator assignment (+= etc.).

  • Use multiple assignment.

  • Use tuple assignment.

  • Use advanced tuple assignment.

  • Use list and string “multiplication.”

  • Return multiple values.

  • Use loops and the else keyword.

  • Take advantage of Booleans and not.

  • Treat strings as lists of characters.

  • Eliminate characters by using replace.

  • Don’t write unnecessary loops.

  • Use chained comparisons.

  • Simulate “switch” with a table of functions.

  • Use the is operator correctly.

  • Use one-line for loops.

  • Squeeze multiple statements onto a line.

  • Write one-line if/then/else statements.

  • Create Enum values with range.

  • Reduce the inefficiency of the print function within IDLE.

  • Place underscores inside large numbers.

Let’s look at these ideas in detail.

4.2.1 Use Python Line Continuation as Needed

In Python, the normal statement terminator is just the end of a physical line (although note the exceptions in Section 3.18). This makes programming easier, because you can naturally assume that statements are one per line.

But what if you need to write a statement longer than one physical line? This dilemma can crop up in a number of ways. For example, you might have a string to print that you can’t fit on one line. You could use literal quotations, but line wraps, in that case, are translated as newlines—something you might not want. The solution, first of all, is to recognize that literal strings positioned next to other literal strings are automatically concatenated.

>>> my_str = 'I am Hen-er-y the Eighth,' ' I am!'
>>> print(my_str)
I am Hen-er-y the Eighth, I am!

If these substrings are too long to put on a single physical line, you have a couple of choices. One is to use the line-continuation character, which is a backslash (\).

my_str = 'I am Hen-er-y the Eighth,' ' I am!'

Another technique is to observe that any open—and so far unmatched—parenthesis, square bracket, or brace automatically causes continuation onto the next physical line. Consequently, you can enter as long a statement as you want—and you can enter a string of any length you want—without necessarily inserting newlines.

my_str = ('I am Hen-er-y the Eighth, '
'I am! I am not just any Henry VIII, '
'I really am!')

This statement places all this text in one string. You can likewise use open parentheses with other kinds of statements.

length_of_hypotenuse = ( (side1 * side1 + side2 * side2)
                          ** 0.5 )

A statement is not considered complete until all open parentheses [(] have been matched by closing parentheses [)]. The same is true for braces and square brackets. As a result, this statement will automatically continue to the next physical line.

4.2.2 Use “for” Loops Intelligently

If you come from the C/C++ world, you may tend to overuse the range function to print members of a list. Here’s an example of the C way of writing a for loop, using range and an indexing operation.

beat_list = ['John', 'Paul', 'George', 'Ringo']
for i in range(len(beat_list)):
    print(beat_list[i])

If you ever write code like this, you should try to break the habit as soon as you can. It’s better to print the contents of a list or iterator directly.

beat_list = ['John', 'Paul', 'George', 'Ringo']
for guy in beat_list:
    print(guy)

Even if you need access to a loop variable, it’s better to use the enumerate function to generate such numbers. Here’s an example:

beat_list = ['John', 'Paul', 'George', 'Ringo']
for i, name in enumerate(beat_list, 1):
    print(i, '. ', name, sep='')

This prints

1. John
2. Paul
3. George
4. Ringo

There are, of course, some cases in which it’s necessary to use indexing. That happens most often when you are trying to change the contents of a list in place.

4.2.3 Understand Combined Operator Assignment (+= etc.)

The combined operator-assignment operators are introduced in Chapter 1 and so are reviewed only briefly here. Remember that assignment (=) can be combined with any of the following operators: +, -, /, //, %, **, &, ^, |, <<, >>.

The operators &, |, and ^ are bitwise “and,” “or,” and “exclusive or,” respectively. The operators << and >> perform bit shifts to the left and to the right.

This section covers some finer points of operator-assignment usage. First, any assignment operator has low precedence and is carried out last.

Second, an assignment operator may or may not be in place, depending on whether the type operated on is mutable. In place refers to operations that work on existing data in memory rather than creating a completely new object. Such operations are faster and more efficient.

Integers, floating-point numbers, and strings are immutable. Assignment operators, used with these types, do not cause in-place assignment; they instead must produce a completely new object, which is reassigned to the variable. Here’s an example:

s1 = s2 = 'A string.'
s1 += '...with more stuff!'
print('s1:', s1)
print('s2:', s2)

The print function, in this case, produces the following output:

s1: A string...with more stuff!
s2: A string.

When s1 was assigned a new value, it did not change the string data in place; it assigned a whole new string to s1. But s2 is a name that still refers to the original string data. This is why s1 and s2 now contain different strings.

But lists are mutable, and therefore changes to lists can occur in place.

a_list = b_list = [10, 20]
a_list += [30, 40]
print('a_list:', a_list)
print('b_list:', b_list)

This code prints

a_list: [10, 20, 30, 40]
b_list: [10, 20, 30, 40]

In this case, the change was made to the list in place, so there was no need to create a new list and reassign that list to the variable. Therefore, a_list was not assigned to a new list, and b_list, a variable that refers to the same data in memory, reflects the change as well.

In-place operations are almost always more efficient. In the case of lists, Python reserves some extra space to grow when allocating a list in memory, and that in turns permits append operations, as well as +=, to efficiently grow lists. However, occasionally lists exceed the reserved space and must be moved. Such memory management is seamless and has little or no impact on program behavior.

Non-in-place operations are less efficient, because a new object must be created. That’s why it’s advisable to use the join method to grow large strings rather than use the += operator, especially if performance is important. Here’s an example using the join method to create a list and join 26 characters together.

str_list = []
n = ord('a')
for i in range(n, n + 26):
     str_list += chr(i)
alphabet_str = ''.join(str_list)

Figures 4.1 and 4.2 illustrate the difference between in-place operations and non-in-place operations. In Figure 4.1, string data seems to be appended onto an existing string, but what the operation really does is to create a new string and then assign it to the variable—which now refers to a different place in memory.

FIGURE 4.1

Figure 4.1. Appending to a string (not in-place)

But in Figure 4.2, list data is appended onto an existing list without the need to create a new list and reassign the variable.

FIGURE 4.2

Figure 4.2. Appending to a list (in-place)

Here’s a summary:

  • Combined assignment operators such as += cause in-place changes to data if the object is mutable (such as a list); otherwise, a whole new object is assigned to the variable on the left.

  • In-place operations are faster and use space more efficiently, because they do not force creation of a new object. In the case of lists, Python usually allocates extra space so that the list can be grown more efficiently at run time.

4.2.4 Use Multiple Assignment

Multiple assignment is one of the most commonly used coding shortcuts in Python. You can, for example, create five different variables at once, assigning them all the same value—in this case, 0:

a = b = c = d = e = 0

Consequently, the following returns True:

a is b

This statement would no longer return True if either of these variables was later assigned to a different object.

Even though this coding technique may look like it is borrowed from C and C++, you should not assume that Python follows C syntax in most respects. Assignment in Python is a statement and not an expression, as it is in C.

4.2.5 Use Tuple Assignment

Multiple assignment is useful when you want to assign a group of variables the same initial value.

But what if you want to assign different values to different variables? For example, suppose you want to assign 1 to a, and 0 to b. The obvious way to do that is to use the following statements:

a = 1
b = 0

But through tuple assignment, you can combine these into a single statement.

a, b = 1, 0

In this form of assignment, you have a series of values on one side of the equals sign (=) and another on the right. They must match in number, with one exception: You can assign a tuple of any size to a single variable (which itself now represents a tuple as a result of this operation).

a = 4, 8, 12   # a is now a tuple containing three values.

Tuple assignment can be used to write some passages of code more compactly. Consider how compact a Fibonacci-generating function can be in Python.

def fibo(n):
    a, b = 1, 0
    while a <= n:
        print(a, end=' ')
        a, b = a + b, a

In the last statement, the variable a gets a new value: a + b; the variable b gets a new value—namely, the old value of a.

Most programming languages have no way to set a and b simultaneously. Setting the value of a changes what gets put into b, and vice versa. So normally, a temporary variable would be required. You could do that in Python, if you wanted to:

temp = a     # Preserve old value of a
a = a + b    # Set new value of a
b = temp     # Set b to old value of a

But with tuple assignment, there’s no need for a temporary variable.

a, b = a + b, a

Here’s an even simpler example of tuple assignment. Sometimes, it’s useful to swap two values.

x, y = 1, 25
print(x, y)   # prints 1 25
x, y = y, x
print(x, y)   # prints 25 1

The interesting part of this example is the statement that performs the swap:

x, y = y, x

In another language, such an action would require three separate statements. But Python does not require this, because—as just shown—it can do the swap all at once. Here is what another language would require you to do:

temp = x
x = y
y = temp

4.2.6 Use Advanced Tuple Assignment

Tuple assignment has some refined features. For example, you can unpack a tuple to assign to multiple variables, as in the following example.

tup = 10, 20, 30
a, b, c = tup
print(a, b, c)   # Produces 10, 20, 30

It’s important that the number of input variables on the left matches the size of the tuple on the right. The following statement would produce a runtime error.

tup = 10, 20, 30
a, b = tup   # Error: too many values to unpack

Another technique that’s occasionally useful is creating a tuple that has one element. That would be easy to do with lists.

my_list = [3]

This is a list with one element, 3. But the same approach won’t work with tuples.

my_tup = (3)
print(type(my_tup))

This print statement shows that my_tup, in this case, produced a simple integer.

<class 'int'>

This is not what was wanted in this case. The parentheses were treated as a no-op, as would any number of enclosing parentheses. But the following statement produces a tuple with one element, although, to be fair, a tuple with just one element isn’t used very often.

my_tup = (3,)     # Assign tuple with one member, 3.

The use of an asterisk (*) provides a good deal of additional flexibility with tuple assignment. You can use it to split off parts of a tuple and have one (and only one) variable that becomes the default target for the remaining elements, which are then put into a list. Some examples should make this clear.

a, *b = 2, 4, 6, 8

In this example, a gets the value 2, and b is assigned to a list:

2
[4, 6, 8]

You can place the asterisk next to any variable on the left, but in no case more than one. The variable modified with the asterisk is assigned a list of whatever elements are left over. Here’s an example:

a, *b, c = 10, 20, 30, 40, 50

In this case, a and c refer to 10 and 50, respectively, after this statement is executed, and b is assigned the list [20, 30, 40].

You can, of course, place the asterisk next to a variable at the end.

big, bigger, *many = 100, 200, 300, 400, 500, 600

Printing these variables produces the following:

>>> print(big, bigger, many, sep='\n')
100
200
[300, 400, 500, 600]

4.2.7 Use List and String “Multiplication”

Serious programs often deal with large data sets—for example, a collection of 10,000 integers all initialized to 0. In languages such as C and Java, the way to do this is to first declare an array with a large dimension.

Because there are no data declarations in Python, the only way to create a large list is to construct it on the right side of an assignment. But constructing a super-long list by hand is impractical. Imagine trying to construct a super-long list this way:

my_list = [0, 0, 0, 0, 0, 0, 0, 0...]

As you can imagine, entering 10,000 zeros into program code would be very time-consuming! And it would make your hands ache.

Applying the multiplication operator provides a more practical solution:

my_list = [0] * 10000

This example creates a list of 10,000 integers, all initialized to 0.

Such operations are well optimized in Python, so that even in the interactive development environment (IDLE), such interactions are handled quickly.

>>> my_list = [0] * 10000
>>> len(my_list)
10000

Note that the integer may be either the left or the right operand in such an expression.

>>> my_list = 1999 * [12]
>>> len(my_list)
1999

You can also “multiply” longer lists. For example, the following list is 300 elements long. It consists of the numbers 1, 2, 3, repeated over and over.

>>> trip_list = [1, 2, 3] * 100
>>> len(trip_list)
300

The multiplication sign (*) does not work with dictionaries and sets, which require unique keys. But it does work with the string class (str); for example, you can create a string consisting of 40 underscores, which you might use for display purposes:

divider_str = '_' * 40

Printing out this string produces the following:

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

4.2.8 Return Multiple Values

You can’t pass a simple variable to a Python function, change the value inside the function, and expect the original variable to reflect the change. Here’s an example:

def double_me(n):
    n *= 2

a = 10
double_me(a)
print(a)        # Value of a did not get doubled!!

When n is assigned a new value, the association is broken between that variable and the value that was passed. In effect, n is a local variable that is now associated with a different place in memory. The variable passed to the function is unaffected.

But you can always use a return value this way:

def double_me(n):
    return n * 2

a = 10
a = double_me(a)
print(a)

Therefore, to get an out parameter, just return a value. But what if you want more than one out parameter?

In Python, you can return as many values as you want. For example, the following function performs the quadratic equation by returning two values.

def quad(a, b, c):
    determin = (b * b - 4 * a * c) ** .5
    x1 = (-b + determin) / (2 * a)
    x2 = (-b - determin) / (2 * a)
    return x1, x2

This function has three input arguments and two output variables. In calling the function, it’s important to receive both arguments:

x1, x2 = quad(1, -1, -1)

If you return multiple values to a single variable in this case, that variable will store the values as a tuple. Here’s an example:

>>> x = quad(1, -1, -1)
>>> x
(1.618033988749895, -0.6180339887498949)

Note that this feature—returning multiple values—is actually an application of the use of tuples in Python.

4.2.9 Use Loops and the “else” Keyword

The else keyword is most frequently used in combination with the if keyword. But in Python, it can also be used with try-except syntax and with loops.

With loops, the else clause is executed if the loop has completed without an early exit, such as break. This feature applies to both while loops and for loops.

The following example tries to find an even divisor of n, up to and including the limit, max. If no such divisor is found, it reports that fact.

def find_divisor(n, max):
    for i in range(2, max + 1):
        if n % i == 0:
            print(i, 'divides evenly into', n)
            break
    else:
        print('No divisor found')

Here’s an example:

>>> find_divisor(49, 6)
No divisor found
>>> find_divisor(49, 7)
7 divides evenly into 49

4.2.10 Take Advantage of Boolean Values and “not”

Every object in Python evaluates to True or False. For example, every empty collection in Python evaluates to False if tested as a Boolean value; so does the special value None. Here’s one way of testing a string for being length zero:

if len(my_str) == 0:
    break

However, you can instead test for an input string this way:

if not s:
     break

Here are the general guidelines for Boolean conversions.

  • Nonempty collections and nonempty strings evaluate as True; so do nonzero numeric values.

  • Zero-length collections and zero-length strings evaluate to False; so does any number equal to 0, as well as the special value None.

4.2.11 Treat Strings as Lists of Characters

When you’re doing complicated operations on individual characters and building a string, it’s sometimes more efficient to build a list of characters (each being a string of length 1) and use list comprehension plus join to put it all together.

For example, to test whether a string is a palindrome, it’s useful to omit all punctuation and space characters and convert the rest of the string to either all-uppercase or all-lowercase. List comprehension does this efficiently.

test_str = input('Enter test string: ')
a_list = [c.upper() for c in test_str if c.isalnum()]
print(a_list == a_list[::-1])

The second line in this example uses list comprehension, which was introduced in Section 3.15, “List Comprehension.”

The third line in this example uses slicing to get the reverse of the list. Now we can test whether test_str is a palindrome by comparing it to its own reverse. These three lines of code have to be the shortest possible program for testing whether a string is a palindrome. Talk about compaction!

Enter test string: A man, a plan, a canal, Panama!
True

4.2.12 Eliminate Characters by Using “replace”

To quickly remove all instances of a particular character from a string, use replace and specify the empty string as the replacement.

For example, a code sample in Chapter 10 asks users to enter strings that represent fractions, such as “1/2”. But if the user puts extra spaces in, as in “1 / 2”, this could cause a problem. Here’s some code that takes an input string, s, and quickly rids it of all spaces wherever they are found (so it goes beyond stripping):

s = s.replace(' ', '')

Using similar code, you can quickly get rid of all offending characters or substrings in the same way—but only one at a time. Suppose, however, that you want to get rid of all vowels in one pass. List comprehension, in that case, comes to your aid.

a_list = [c for c in s if c not in 'aeiou']
s = ''.join(a_list)

4.2.13 Don’t Write Unnecessary Loops

Make sure that you don’t overlook all of Python’s built-in abilities, especially when you’re working with lists and strings. With most computer languages, you’d probably have to write a loop to get the sum of all the numbers in a list. But Python performs summation directly. For example, the following function calculates 1 + 2 + 3 … + N:

def calc_triangle_num(n):
     return sum(range(n+1))

Another way to use the sum function is to quickly get the average (the mean) of any list of numbers.

def get_avg(a_list):
    return sum(a_list) / len(a_list)

4.2.14 Use Chained Comparisons (n < x < m)

This is a slick little shortcut that can save you a bit of work now and then, as well as making your code more readable.

It’s common to write if conditions such as the following:

if 0 < x and x < 100:
    print('x is in range.')

But in this case, you can save a few keystrokes by instead using this:

if 0 < x < 100:        # Use 'chained' comparisons.
    print('x is in range.')

This ability potentially goes further. You can chain together any number of comparisons, and you can include any of the standard comparison operators, including ==, <, <=, >, and >=. The arrows don’t even have to point in the same direction or even be combined in any order! So you can do things like this:

a, b, c = 5, 10, 15
if 0 < a <= c > b > 1:
    print('All these comparisons are true!')
    print('c is equal or greater than all the rest!')

You can even use this technique to test a series of variables for equality. Here’s an example:

a = b = c = d = e = 100
if a == b == c == d == e:
    print('All the variables are equal to each other.')

For larger data sets, there are ways to achieve these results more efficiently. Any list, no matter how large, can be tested to see whether all the elements are equal this way:

if min(a_list) == max(a_list):
    print('All the elements are equal to each other.')

However, when you just want to test a few variables for equality or perform a combination of comparisons on a single line, the techniques shown in this section are a nice convenience with Python. Yay, Python!

4.2.15 Simulate “switch” with a Table of Functions

This next technique is nice because it can potentially save a number of lines of code.

Section 15.12 offers the user a menu of choices, prompts for an integer, and then uses that integer to decide which of several functions to call. The obvious way to implement this logic is with a series of if/elif statements, because Python has no “switch” statement.

if n == 1:
    do_plot(stockdf)
elif n == 2:
    do_highlow_plot(stockdf)
elif n == 3:
    do_volume_subplot(stockdf)
elif n == 4:
    do_movingavg_plot(stockdf)

Code like this is verbose. It will work, but it’s longer than it needs to be. But Python functions are objects, and they can be placed in a list just like any other kind of objects. You can therefore get a reference to one of the functions and call it.

fn = [do_plot, do_highlow_plot, do_volume_subplot,
      do_movingavg_plot][n-1]
fn(stockdf)                 # Call the function

For example, n-1 is evaluated, and if that value is 0 (that is, n is equal to 1), the first function listed, do_plot, is executed.

This code creates a compact version of a C++ switch statement by calling a different function depending on the value of n. (By the way, the value 0 is excluded in this case, because that value is used to exit.)

You can create a more flexible control structure by using a dictionary combined with functions. For example, suppose that “load,” “save,” “update,” and “exit” are all menu functions. We might implement the equivalent of a switch statement this way:

menu_dict = {'load':load_fn, 'save':save_fn,
             'exit':exit_fn, 'update':update_fn}
(menu_dict[selector])()       # Call the function

Now the appropriate function will be called, depending on the string contained in selector, which presumably contains 'load', 'save', 'update', or 'exit'.

4.2.16 Use the “is” Operator Correctly

Python supports both a test-for-equality operator (==) and an is operator. These tests sometimes return the same result, and sometimes they don’t. If two strings have the same value, a test for equality always produces True.

a = 'cat'
b = 'cat'
a == b    # This must produce True.

But the is operator isn’t guaranteed to produce True in string comparisons, and it’s risky to rely upon. A constructed string isn’t guaranteed to match another string if you use is rather than test-for-equality (==). For example:

>>> s1 = 'I am what I am and that is all that I am.'
>>> s2 = 'I am what I am' + ' and that is all that I am.'
>>> s1 == s2
True
>>> s1 is s2
False

What this example demonstrates is that just because two strings have identical contents does not mean that they correspond to the same object in memory, and therefore the is operator produces False.

If the is operator is unreliable in such cases, why is it in the language at all? The answer is that Python has some unique objects, such as None, True, and False. When you’re certain that you’re comparing a value to a unique object, then the is keyword works reliably; moreover, it’s preferable in those situations because such a comparison is more efficient.

a_value = my_function()
if a_value is None:
    # Take special action if None is returned.

4.2.17 Use One-Line “for” Loops

If a for loop is short enough, with only one statement inside the loop (that is, the statement body), you can squeeze the entire for loop onto a single physical line.

key.jpg
for var in sequence: statement

Not all programmers favor this programming style. However, it’s useful as a way of making your program more compact. For example, the following one-line statement prints all the numbers from 0 to 9:

>>> for i in range(10): print(i, end='  ')

0  1  2  3  4  5  6  7  8  9

Notice that when you’re within IDLE, this for loop is like any other: You need to type an extra blank line in order to terminate it.

4.2.18 Squeeze Multiple Statements onto a Line

If you have a lot of statements you want to squeeze onto the same line, you can do it—if you’re determined and the statements are short enough.

The technique is to use a semicolon (;) to separate one statement on a physical line from another. Here’s an example:

>>> for i in range(5): n=i*2; m = 5; print(n+m, end=' ')

5 7 9 11 13

You can squeeze other kinds of loops onto a line in this way. Also, you don’t have to use loops but can place any statements on a line that you can manage to fit there.

>>> a = 1; b = 2; c = a + b; print(c)
3

At this point, some people may object, “But with those semicolons, this looks like C code!” (Oh, no—anything but that!)

Maybe it does, but it saves space. Keep in mind that the semicolons are statement separators and not terminators, as in the old Pascal language.

4.2.19 Write One-Line if/then/else Statements

This feature is also called an in line if conditional. Consider the following if/else statement, which is not uncommon:

turn = 0
...
if turn % 2:
    cell = 'X'
else:
    cell = 'O'

The book Python Without Fear uses this program logic to help operate a tic-tac-toe game. On alternate turns, the cell to be added was either an “X” or an “O”. The turn counter, advanced by 1 each time, caused a switch back and forth (a toggle) between the two players, “X” and “O.”

That book replaced the if/else block just shown with the more compact version:

cell = 'X' if turn % 2 else 'O'
true_expr if conditional else false_expr
key.jpg

If the conditional is true, then the true_expr is evaluated and returned; otherwise the false_expr is evaluated and returned.

4.2.20 Create Enum Values with “range”

Many programmers like to use enumerated (or “enum”) types in place of so-called magic numbers. For example, if you have a color_indicator variable, in which the values 1 through 5 represent the values red, green, blue, back, and white, the code becomes more readable if you can use the color names instead of using the literal numbers 1 through 5.

You could make this possible by assigning a number to each variable name.

red  = 0
blue = 1
green = 2
black = 3
white = 4

This works fine, but it would be nice to find a way to automate this code. There is a simple trick in Python that allows you to do that, creating an enumeration. You can take advantage of multiple assignment along with use of the range function:

red, blue, green, black, white = range(5)

The number passed to range in this case is the number of settings. Or, if you want to start the numbering at 1 instead of 0, you can use the following:

red, blue, green, black, white = range(1, 6)

4.2.21 Reduce the Inefficiency of the “print” Function Within IDLE

Within IDLE, calls to the print statement are incredibly slow. If you run programs from within the environment, you can speed up performance dramatically by reducing the number of separate calls to print.

For example, suppose you want to print a 40 × 20 block of asterisks (*). The slowest way to do this, by far, is to print each character individually. Within IDLE, this code is painfully slowly.

for i in range(20):
    for j in range(40):
        print('*', end='')
    print()

You can get much better performance by printing a full row of asterisks at a time.

row_of_asterisks = '*' * 40
for i in range(20):
    print(row_of_asterisks)

But the best performance is achieved by revising the code so that it calls the print function only once, after having assembled a large, multiline output string.

row_of_asterisks = '*' * 40
s = ''
for i in range(20):
    s += row_of_asterisks + '\n'
print(s)

This example can be improved even further by utilizing the string class join method. The reason this code is better is that it uses in-place appending of a list rather than appending to a string, which must create a new string each time.

row_of_asterisks = '*' * 40
list_of_str = []
for i in range(20):
    list_of_str.append(row_of_asterisks)
print('\n'.join(list_of_str))

Better yet, here is a one-line version of the code!

print('\n'.join(['*' * 40] * 20))

4.2.22 Place Underscores Inside Large Numbers

In programming, you sometimes have to deal with large numeric literals. Here’s an example:

CEO_salary = 1500000

Such numbers are difficult to read in programming code. You might like to use commas as separators, but commas are reserved for other purposes, such as creating lists. Fortunately, Python provides another technique: You can use underscores (_) inside a numeric literal.

CEO_salary = 1_500_000

Subject to the following rules, the underscores can be placed anywhere inside the number. The effect is for Python to read the number as if no underscores were present. This technique involves several rules.

  • You can’t use two underscores in a row.

  • You can’t use a leading or trailing underscore. If you use a leading underscore (as in _1), the figure is treated as a variable name.

  • You can use underscores on either side of a decimal point.

This technique affects only how numbers appear in the code itself and not how anything is printed. To print a number with thousands-place separators, use the format function or method as described in Chapter 5, “Formatting Text Precisely.”

  • + Share This
  • 🔖 Save To Your Account