Embercode
✕
Variables and Data TypesLesson 7 of 16

35 min read

Literals and number bases in Python

Why this matters

A program often needs a number written directly in the source code. A colour is written as 0xFF8800. A file permission is written as 0o755. A large population count is written as 8_000_000_000. Each of these is a literal, which means a value written out in full in the code, as opposed to a value worked out while the program runs.

The same number can be written in several ways. The number 255 can be written as 255, as 0xFF, as 0b11111111 and as 0o377. All four are the same value. The different spellings exist because programmers think about numbers in different bases, which is the subject of this lesson. A beginner who does not know the rules can misread a literal, for example by writing a leading zero and expecting a decimal number. Python refuses that literal with an error, which is a better result than a silent wrong answer. This lesson teaches the four spellings, the digit separator, and what each literal means, so you can predict the value of a number before you run the code.

What a number base is

A base is the number of digit symbols a system uses. Everyday counting uses base 10, which is called decimal. It has ten symbols, 0 to 9. The place of a digit decides how much it is worth. In the number 325, the 3 means 3 hundreds, the 2 means 2 tens, and the 5 means 5 ones. Each place is worth ten times the place on its right.

Base 2 is binary. It has two symbols, 0 and 1. Each place is worth twice the place on its right. Base 16 is hexadecimal, often shortened to hex. It has sixteen symbols, 0 to 9 and then the letters A to F, where A means 10 and F means 15. Each place is worth sixteen times the place on its right. Base 8 is octal. It has eight symbols, 0 to 7.

Here is one number counted in each base, with its place values written out. Work through the first row, then compare the others.

BaseDigits usedWritten asPlace values from the rightValue
100 to 92555, 5 x 10, 2 x 100255
20 and 1111111111, 2, 4, 8, 16, 32, 64, 128 (all eight 1s)255
160 to 9, A to FFFF x 1, F x 16255
80 to 73777 x 1, 7 x 8, 3 x 64255

The four rows describe one amount of things. The digits change, but the number does not. Python lets you type a literal in any of the four bases, and then it stores the same value. The rest of this lesson shows how to write each spelling.

Decimal literals

A decimal literal is the normal way to write a number. Any sequence of digits that does not start with 0 is a decimal literal. A single 0 on its own is also decimal.

Python · editable
42
0
-7

The minus sign is not part of the literal. Python reads -7 as the operator - applied to the literal 7. For almost every program this makes no difference.

Hexadecimal literals

A hexadecimal literal starts with 0x or 0X. The letters after the prefix can be upper case or lower case. Programmers use hex because it is short. Every hex digit stands for exactly four binary digits, so a two-digit hex number is a byte, eight binary digits, written in two characters. Colours in web pages and memory addresses in debugger output use hex for this reason.

Python · editable
0xFF = 255
0xff = 255
0x1A = 26
0x1A written in decimal: 1 x 16 + 10 = 26

The last line checks the hex value by hand. In 0x1A the digit 1 is worth 16 and the digit A is worth 10, so the total is 26. Doing this by hand once is a good way to learn the rule.

Binary literals

A binary literal starts with 0b or 0B. Each digit is 0 or 1, and each digit is one bit. Binary literals are the clearest way to write a pattern of bits, such as a set of on and off switches.

Python · editable
0b101   = 5
0b10000 = 16
0b1111  = 15

The value 0b101 is 1 x 4 + 0 x 2 + 1 x 1, which is 5. The value 0b10000 has a single 1 in the fifth place from the right, which is worth 16. The binary spelling makes the place value easy to see, but it is long for big numbers. A 32-bit value needs up to 32 binary digits, which is why a separator helps.

Octal literals, and why a leading zero is an error

An octal literal starts with 0o or 0O, followed by digits 0 to 7. Python uses this prefix for octal. Many other languages, including C and Java, use a single leading zero for octal. Python does not. A number with a leading zero is an error, so the trap that changes a number silently in other languages stops the program in Python.

Python · editable
10 in decimal = 10
0o10 in octal = 8
0o77 in octal = 63
0 on its own = 0

The literal 0o10 is not ten. It is 1 x 8 + 0 x 1, which is eight. The literal 0o77 is 7 x 8 + 7 x 1, which is 63. Unix file permissions such as 0o755 are octal for this reason. The 0o prefix tells Python the number is octal.

A common accident happens when someone writes a year, a page number or a zip code with a leading zero, such as 09. Python refuses it, and the message is shown in the Common mistakes section below.

Digit separators

A digit separator is an underscore placed between digits to make a long literal easier to read. Python ignores the underscores when it builds the value, so 1_000_000 and 1000000 are the same number. The separator works in any base.

Python · editable
million = 1000000
0xFF_FF = 65535
0b1010_0101 = 165
population = 8000000000

The binary literal 0b1010_0101 is easier to read in two groups of four bits than as one run of eight digits. Hex and binary literals are most often split this way, into groups of four, so each group matches one hex digit.

There are rules for where the underscore may go. It may appear between two digits. It may come directly after a base prefix, so 0x_FF is legal and has the value 255. It may not be the last character of a literal, so 1_000_ is an error. It may not sit next to a decimal point, so 1_.5 is an error. The messages are shown in the Common mistakes section.

What each literal means

Python has one kind of whole number, int. You do not add a suffix to make a big number a different kind, and you do not choose a size. A literal such as 10000000000 is an int with no limit other than memory. The size rules that matter in languages with fixed-size numbers do not apply here.

Python · editable
small = 2000000000 <class 'int'>
big = 2000000000000 <class 'int'>
small + small = 4000000000
a very large int = 1267650600228229401496703205376

The sum of two large numbers is exact, and the result is still an int. The power 2 ** 100 is a number with 31 digits, and Python prints all of them.

A literal with a decimal point, or with an exponent such as 1e3, is a float. A float stores a decimal number in binary, so it has limited precision, as the type conversion lesson showed. Python has no f suffix for floats, so the literal 2.5f is an error.

Python · editable
1000.0 <class 'float'>
2.5 <class 'float'>
1000.5

Hex and binary literals are also int values, and their bits are read as a positive number. The literal 0xFFFFFFFF is 4294967295, not -1. The value -1 appears only when you ask a fixed-size type to hold those 32 bits, for example with the ctypes module. The next program shows the difference.

Python · editable
4294967295
-1
0xffffffff

The first line is the plain value. The second line reads the same 32 bits as a signed 32-bit number, where the top bit means negative, so the answer is -1. The third line shows the number in hex again. The reason why the top bit is treated as a sign is the subject of the two's complement lesson.

Converting numbers to and from text

Programs often need to show a number in a base other than decimal, or read a number that a user typed in another base. Python has built-in functions for both jobs.

bin, oct and hex each take an int and return a string with the prefix. format takes a number and a format code, and returns the text without the prefix. int takes a string and an optional base, and returns the number.

Python · editable
0b11111111 0o377 0xff
11111111 377 ff
255 10 511
255

Notice that bin, oct and hex return the prefix, and format does not. The prefix belongs to the literal in source code, and the text form is a choice. int also accepts the prefix when the base matches, which is why int("0xff", 16) works.

When the base is given to int, a leading zero is allowed in the text, because the text is not source code. int("0755", 8) is 493, the same value as 0o755. The literal 0755 in source code is an error, and the text "0755" read with the base 8 is fine.

Worked example: the same colour written in parts

A colour on a web page is often written as three numbers, for red, green and blue, each from 0 to 255. In hex, the red part is the first two digits, the green part is the next two, and the blue part is the last two. An orange colour is 0xFF8800, which means red 255, green 136 and blue 0.

The program below stores one colour as a hex literal and then splits it into its three parts. The >> operator moves the bits to the right by a number of places, and & keeps only the bits that are 1 in both numbers. The bitwise operations lesson covers both in full, so this program uses them only as a short helper.

Python · editable
orange = 0xff8800
red   = 255 (0xff)
green = 136 (0x88)
blue  = 0 (0x0)

The red part is 0xFF0000 shifted right 16 bits, which leaves 0xFF, or 255. The green part is 0x8800 shifted right 8 bits, which leaves 0x88, or 136. The blue part is the lowest 8 bits, which are 00, so it is 0. Hex text of 0 is 0x0 when the prefix is added.

The step & 0xFF keeps only the lowest 8 bits of a number. Without it, the green value would be 0xFF88, which still contains the red part.

Common mistakes

The first mistake is a leading zero on a number meant as decimal. Python stops with this message:

  File ".../leading.py", line 1
    print(09)
          ^
SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers

The fix is to remove the leading zero, so 09 becomes 9. If you really want octal, write 0o followed by digits 0 to 7.

The second mistake is a digit that does not belong to the base. A binary literal may contain only 0 and 1:

  File ".../binary.py", line 1
    print(0b102)
              ^
SyntaxError: invalid digit '2' in binary literal

The third mistake is a misplaced underscore. An underscore may not end a literal:

  File ".../underscore.py", line 1
    print(1_000_)
               ^
SyntaxError: invalid decimal literal

The fourth mistake is the f suffix that other languages use for float literals. Python does not have it:

  File ".../suffix.py", line 1
    print(2.5f)
            ^
SyntaxError: invalid decimal literal

The fix is to write 2.5.

The fifth mistake is a byte value that is out of range. A bytes object holds only the values 0 to 255:

Traceback (most recent call last):
  File ".../bytes.py", line 1, in <module>
    print(bytes([256]))
          ~~~~~^^^^^^^
ValueError: bytes must be in range(0, 256)

The sixth mistake is a prefix that the text does not match. int("0x", 16) has the prefix and no digits, so it fails:

Traceback (most recent call last):
  File ".../prefix.py", line 1, in <module>
    print(int("0x", 16))
          ~~~^^^^^^^^^^
ValueError: invalid literal for int() with base 16: '0x'

Practice

Work each exercise yourself before you open the answer. Predict the output on paper first.

  1. What decimal value does each literal stand for? Write the three answers: 0x1F, 0b11001 and 0o31.
  2. What does this program print? x = 0xFFFFFFFF followed by print(x) and print(ctypes.c_int32(x).value), with import ctypes at the top.
  3. The line n = 1_000_000_000_000 is a valid Python literal. Explain why it needs no suffix and no special type, and print n to check.
  4. What does print(0o10 + 10) print?
  5. Store the binary literal 0b1111_1111 in a name and print it in hexadecimal without the prefix. Write the two lines of code and the output.

Each exercise has an answer below a "Show the answer" line. Try each one first, then read the answer.

  1. The hex value is 1 x 16 + 15 = 31. The binary value is 16 + 8 + 1 = 25. The octal value is 3 x 8 + 1 = 25.

Show the answer

print(0x1F, 0b11001, 0o31)

The output is 31 25 25.

  1. The first line prints 4294967295 and the second prints -1.

Show the answer

import ctypes
 
x = 0xFFFFFFFF
print(x)
print(ctypes.c_int32(x).value)

The int holds the value 4294967295, and the ctypes 32-bit signed type reads the same bits as -1.

  1. Python int has no size limit, so the literal stores exactly one trillion with no suffix.

Show the answer

n = 1_000_000_000_000
print(n)

The output is 1000000000000.

  1. The literal 0o10 is 8, and adding 10 gives 18.

Show the answer

print(0o10 + 10)

The output is 18.

  1. The eight ones make 255, which is ff in hex. The format function gives the text without the prefix.

Show the answer

value = 0b1111_1111
print(format(value, "x"))

The output is ff.

What you now know

  • A literal is a value written in full in the source code. Python accepts decimal, hexadecimal, binary and octal forms of whole numbers.
  • A hex literal starts with 0x, a binary literal starts with 0b, and an octal literal starts with 0o.
  • A leading zero on a decimal literal is an error, so 010 cannot silently mean 8.
  • An underscore inside a literal is a digit separator. It may not end a literal or sit next to a decimal point.
  • Every whole-number literal is an int, with no size limit. A hex or binary literal is positive, and the ctypes module reads the same bits as a signed number when you ask for it.
  • bin, oct and hex return text with the prefix. format returns text without it. int(text, base) reads text in any base.
Check yourself: Literals and bases (6 questions) →Practice this topic: coding problems for Variables and Data Types →

Stuck? Ask the tutor

Ask about anything in this lesson. Answers are short and use simple words.

Sign in to ask the tutor.

← Module assignment: Input Stats Report