Python Module 2 – Values, variables, numbers and strings
Type conversion, number bases and bitwise operators
Convert between str, int, float and bool explicitly, read and write binary, octal and hexadecimal, and use Python's bitwise operators to work with bit flags.
What you will learn
- Convert between str, int, float and bool explicitly
- Read and write binary, octal and hexadecimal values
- Use &, |, ^, ~, << and >> to work with bit flags
Before you start
On this page
Python never turns text into a number, or a number into text, to make an operation work. "3" + 4 does not give 7
or "34": it raises TypeError, because a string and a number cannot be added. (Numbers of different types do mix:
in 1 + 2.5 the int is widened to a float, so the result is 3.5.) When you need a number from text, or text from
a number, you say so by calling the type you want. This lesson covers those conversions, the other ways of writing
whole numbers (binary, octal and hexadecimal), and the operators that work on the individual bits of a number.
Converting between str, int and float
Each built-in type’s name converts a value to that type: int(), float(), str() and bool().
# Each type's name converts a value to that type.
print(int("42") + 1, float("2.5") * 2, str(42) + "!")
# int() accepts spaces around the digits, a sign and underscores between digits.
print(int(" 7\n"), int("-12"), int("1_000"))
# From a float, int() cuts off the fraction (towards zero); round() rounds instead.
print(int(7.9), int(-7.9), round(7.9))
print(float("1e3"), float(" -0.5 "), float("inf"))
print(str(3.0), str(True), repr("3"))
# Text that is not written as a whole number raises ValueError, even "7.0".
for text in ["7.5", "7.0", "seven", ""]:
try:
int(text)
except ValueError as error:
print(error)
print(int(float("7.5"))) Output
43 5.0 42! 7 -12 1000 7 -7 8 1000.0 -0.5 inf 3.0 True '3' invalid literal for int() with base 10: '7.5' invalid literal for int() with base 10: '7.0' invalid literal for int() with base 10: 'seven' invalid literal for int() with base 10: '' 7
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 conversions.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
int(text)accepts spaces and line breaks around the digits, a+or-sign, and single underscores between digits. As the string-methods lesson showed, it reads decimal digits of other scripts too, such as"७".int()reads whole numbers only, so text with a decimal point raisesValueError:int("7.5")does, and so doesint("7.0"). Read it withfloat()first when that is what you mean:int(float("7.5"))is 7. (A float has limited precision, so a very long number loses its last digits on the way;decimal.Decimalkeeps them all.)- From a float,
int()drops the fraction and moves towards zero:int(7.9)is 7 andint(-7.9)is -7. Useround()when you want the nearest whole number. float()also reads scientific notation ("1e3") and the special values"inf"and"nan".str()gives the text you would see fromprint().repr()gives the text you would write in code, which is whyrepr("3")shows the quotes: it tells a string"3"apart from the number3.
True or false: bool() and text
bool() follows Python’s rules for truth: zero, None and anything empty are false, and almost everything else is
true. For strings that means the only false string is "":
# bool() of a string asks only one question: is it empty?
print(bool("False"), bool("0"), bool(" "), bool(""))
print(bool(0), bool(0.0), bool(42), bool(None))
answer = "no"
if answer:
print("This line runs, although the answer was no.")
# Text that means yes or no has to be read word by word.
print(answer.strip().casefold() in ("yes", "y", "true", "1")) Output
True True True False False False True False This line runs, although the answer was no. False
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 bool_trap.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
bool("False") is True, and so is bool("0"), because neither string is empty. Settings files, forms and command
lines give you text such as “yes”, “off” or “0”, and the only way to read it as a yes or no is to compare it with the
words you accept, as the last line does and as this lesson’s exercise asks you to do.
Binary, octal and hexadecimal
A whole number has no base of its own: base 10 is only how it is usually written. Python can write and read numbers in base 2 (binary), base 8 (octal) and base 16 (hexadecimal, with the digits a to f for 10 to 15):
n = 493
# bin(), oct() and hex() give text with a prefix; format types b, o, x and X leave it out.
print(bin(n), oct(n), hex(n))
print(f"{n:b} {n:o} {n:x} {n:X} {n:#x}")
print(f"{5:08b}", f"{n:_b}")
# In code, the same prefixes write a number in another base. It is still an ordinary int.
print(0b111101101, 0o755, 0x1ED, 0x1ED == 493)
# int(text, base) reads text in any base from 2 to 36; base 0 follows the prefix.
print(int("755", 8), int("1ed", 16), int("0x1ED", 16), int("0b101", 0))
# A colour code is three hexadecimal numbers, one each for red, green and blue.
colour = "#1E90FF"
print(int(colour[1:3], 16), int(colour[3:5], 16), int(colour[5:7], 16)) Output
0b111101101 0o755 0x1ed 111101101 755 1ed 1ED 0x1ed 00000101 1_1110_1101 493 493 493 True 493 493 493 5 30 144 255
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 bases.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
bin(),oct()andhex()return text with the prefixes0b,0oand0x. The format typesb,o,xandXwrite the digits without the prefix,#adds it, a width with0pads with zeros (08bfor one byte), and_groups the digits in fours.- The same prefixes write numbers in code:
0b111101101,0o755and0x1EDare all the int 493, and nothing about the number remembers how it was written. int(text, base)reads text in any base from 2 to 36 and accepts the matching prefix, soint("0x1ED", 16)works. With base 0, the prefix decides the base, as it does in code.- Hexadecimal is everywhere in computing because one hex digit is exactly four bits: colour codes such as
#1E90FFare three numbers from 0 to 255, one each for red, green and blue.
Characters and their numbers: ord() and chr()
Every character is stored as its Unicode code point, a number. ord() returns the number of a one-character string
and chr() returns the character for a number, so each undoes the other:
# ord() gives the number of a character, and chr() the character of a number.
print(ord("A"), ord("a"), ord("0"), ord("अ"))
print(chr(65), chr(0x905), chr(0x1F40D))
for ch in "अआइ":
print(ch, ord(ch), hex(ord(ch)), chr(ord(ch)) == ch) Output
65 97 48 2309 A अ 🐍 अ 2309 0x905 True आ 2310 0x906 True इ 2311 0x907 True
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 ord_chr.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
The letters A to Z and a to z, and the digits 0 to 9, have consecutive numbers, which is why ord(ch) - ord("0") was
a classic way to turn a digit into its value. chr() accepts numbers from 0 to 0x10FFFF, the largest code point,
and raises ValueError outside that range.
Bitwise operators and bit flags
The bitwise operators treat a whole number as a row of bits and work on each bit position separately:
a & b(and) has a 1 bit wherever bothaandbhave one.a | b(or) has a 1 bit wherevera,bor both have one.a ^ b(exclusive or) has a 1 bit wherever exactly one of them has one.~a(invert) flips every bit; for Python’s ints,~aequals-a - 1.a << n(shift left) moves the bitsnplaces to the left, which is the same asa * 2**n.a >> n(shift right) moves the bitsnplaces to the right and drops the lowestn, the same asa // 2**n.
Their everyday use is bit flags: several yes-or-no settings packed into one number, one bit each. Unix file permissions work that way, with read worth 4, write 2 and execute 1:
READ, WRITE, EXEC = 4, 2, 1
# | combines flags: each flag is one bit.
mode = READ | WRITE
print(mode, f"{mode:03b}")
# & tests a flag: the result is the flag itself, or 0.
print(mode & WRITE, mode & EXEC, bool(mode & WRITE))
# |= switches a flag on, &= ~ switches it off, ^= flips it.
mode |= EXEC
mode &= ~WRITE
print(mode, f"{mode:03b}")
mode ^= READ
print(mode, f"{mode:03b}")
# Three groups of three bits make a Unix permission such as 755.
owner, group, others = 7, 5, 5
permission = owner << 6 | group << 3 | others
print(permission, oct(permission), f"{permission:09b}") Output
6 110 2 0 True 5 101 1 001 493 0o755 111101101
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 permissions.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
| switches flags on, & with a flag tests it (the result is the flag’s value or 0, so wrap it in bool() when you
want True or False), & ~flag switches a flag off, and ^ flips one. Because one octal digit is exactly three
bits, each digit of a permission such as 755 describes one group of users:
One octal digit is three bits
Text description of the diagram
The diagram shows the file permission 755 as nine bits in three groups of three, labelled owner, group and others.
- Each group has three bits for read (r), write (w) and execute (x), worth 4, 2 and 1.
- The owner's bits are 1, 1 and 1, so the owner may read, write and execute: 4 + 2 + 1 is 7.
- The group's bits are 1, 0 and 1, so the group may read and execute but not write: 4 + 1 is 5.
- The bits for others are also 1, 0 and 1, which is 5 again.
- Because one octal digit holds exactly three bits, the three digits 7, 5 and 5 can be read straight off the groups. The line at the bottom says that 0o755 in octal is 0b111101101 in binary and 493 in decimal: three ways of writing the same number.
Note
Python’s enum module has a Flag class that gives each bit a name and prints combinations readably; a later
lesson on enums covers it. The operators underneath are the ones in this lesson.
Negative and very large numbers
Python’s ints have no fixed size, so they have no fixed number of bits either. The documentation describes the bitwise operators as working on two’s complement with an endless supply of sign bits:
# Shifting left multiplies by a power of two; shifting right floor-divides.
print(1 << 10, 1001 >> 3, -1001 >> 3)
# ~x is -x - 1: Python ints behave as if they had endless sign bits.
print(~5, ~-6, -1 >> 10)
print(bin(-5), (-5).bit_count())
# A mask such as 0xFF keeps the lowest 8 bits, which gives the two's complement byte.
print(-5 & 0xFF, f"{-5 & 0xFF:08b}")
# bit_count() (Python 3.10 and newer) counts the ones; bit_length() gives the bits needed.
print((255).bit_count(), (255).bit_length(), (2**100).bit_length())
# Bitwise operators bind more tightly than comparisons, so this means (5 & 2) == 0.
print(5 & 2 == 0) Output
1024 125 -126 -6 5 -1 -0b101 2 251 11111011 8 8 101 True
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 infinite_bits.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
- Shifts multiply and floor-divide by powers of two.
1001 >> 3is 125, while-1001 >> 3is -126: the result is rounded down, exactly like-1001 // 8. And-1 >> 10stays -1 because the sign bits never run out. bin(-5)is'-0b101': a minus sign and the bits of 5, not a row of ones. To see a negative number as the byte a fixed-width language would store, mask it:-5 & 0xFFkeeps the lowest eight bits, 251.bit_length()is the number of bits needed to write a number without its sign, andbit_count()(Python 3.10 and newer) counts its 1 bits, ignoring the sign.- The bitwise operators bind more tightly than comparisons, so
flags & WRITE == 0means(flags & WRITE) == 0. Brackets still make such a line easier to read.
Key takeaways
- Convert explicitly with
int(),float(),str()andbool();int("7.5")raisesValueError,int(7.9)is 7 (towards zero) andround()rounds. - Every non-empty string is true,
"False"included, so read yes-or-no text by comparing it with the words you accept. bin(),oct()andhex()write prefixed text,int(text, base)reads it back, and0b,0oand0xwrite numbers in code.ord()andchr()convert between a character and its code point.&,|,^and~work bit by bit and suit bit flags;<<and>>multiply and floor-divide by powers of two.- Python’s ints act as if they had endless sign bits: mask with
& 0xFF(and so on) when you need a fixed width.
Exercise
Exercise · Easy · Python
Read yes-or-no text and count the bits of a number
Write two small functions in bits.py.
The first, parse_bool(text), reads a yes-or-no setting, as it might appear in a settings file or a form. It returns True for "yes", "true", "on" and "1", and False for "no", "false", "off" and "0", in any mix of upper and lower case and with any spaces around the word: parse_bool(" Yes ") is True and parse_bool("OFF") is False. Any other text, the empty string included, raises ValueError. (bool(text) will not do: bool("False") is True.)
The second, count_set_bits(n), returns how many bits of the whole number n are 1: count_set_bits(255) is 8 and count_set_bits(2**100) is 1. Count them yourself with the bitwise operators & and >>: the function may not use bin(), format(), int.bit_count() or an f-string, and the sample tests check both. A negative n raises ValueError. It must also work for very large numbers, such as 2**4000 - 1.
Starter code · bits.py
def parse_bool(text):
"""Return True or False for words such as 'yes', 'OFF' or '1'; raise ValueError for anything else."""
# Replace this line with your code.
return bool(text)
def count_set_bits(n):
"""Return how many bits of n (0 or more) are 1, without bin(), format(), int.bit_count() or f-strings."""
# Replace this line with your code.
return 0 The sample tests · test_bits.py
import ast
import inspect
import bits
from bits import count_set_bits, parse_bool
def raises_value_error(function, value):
"""True when function(value) raises ValueError."""
try:
function(value)
except ValueError:
return True
return False
def test_true_words():
"""reads yes, true, on and 1 as True, in any case and with spaces around"""
for text in ["yes", "true", "on", "1", " Yes ", "TRUE", "On\n"]:
assert parse_bool(text) is True, f"parse_bool({text!r})"
def test_false_words():
"""reads no, false, off and 0 as False"""
for text in ["no", "false", "off", "0", " NO", "False", "oFF"]:
assert parse_bool(text) is False, f"parse_bool({text!r})"
def test_other_text():
"""raises ValueError for any other text"""
for text in ["", " ", "maybe", "y", "2", "yes please"]:
assert raises_value_error(parse_bool, text), f"parse_bool({text!r}) should raise ValueError"
def test_small_numbers():
"""counts the 1 bits of small numbers"""
assert count_set_bits(0) == 0
assert count_set_bits(1) == 1
assert count_set_bits(0b1011) == 3
assert count_set_bits(255) == 8
assert count_set_bits(256) == 1
def test_large_numbers():
"""counts the 1 bits of very large numbers"""
assert count_set_bits(2**100) == 1
assert count_set_bits(2**100 - 1) == 100
assert count_set_bits(2**4000 - 1) == 4000
assert count_set_bits(10**30) == (10**30).bit_count()
def test_negative():
"""raises ValueError for a negative number"""
assert raises_value_error(count_set_bits, -1)
assert raises_value_error(count_set_bits, -255)
def test_no_shortcuts():
"""counts the bits without bin(), format(), bit_count() or an f-string"""
tree = ast.parse(inspect.getsource(bits.count_set_bits))
for node in ast.walk(tree):
assert not (isinstance(node, ast.Name) and node.id in ("bin", "format")), "bin() and format() are not allowed"
assert not (isinstance(node, ast.Attribute) and node.attr in ("bit_count", "format")), "bit_count() and str.format() are not allowed"
assert not isinstance(node, ast.JoinedStr), "f-strings are not allowed"
def test_bitwise_operators():
"""counts the bits with the bitwise operators & or >>"""
tree = ast.parse(inspect.getsource(bits.count_set_bits))
used = {type(node.op) for node in ast.walk(tree) if isinstance(node, (ast.BinOp, ast.AugAssign))}
assert ast.BitAnd in used or ast.RShift in used, "look at the bits with & or >>, not with % or //" A hint
For parse_bool(), clean the text with strip() and casefold() first, then test it with in against a tuple of the accepted words. For count_set_bits(), n & 1 is the lowest bit of n (0 or 1) and n >> 1 drops that bit, so a loop that adds n & 1 and then shifts n until it is 0 visits every bit once.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Check yourself
5 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.
References
- int() (Built-in Functions) (Python Software Foundation)
- Numeric Types, int, float and complex (The Python Standard Library) (Python Software Foundation)
- Truth Value Testing (The Python Standard Library) (Python Software Foundation)
- Bitwise Operations on Integer Types (The Python Standard Library) (Python Software Foundation)
- int.bit_count() and int.bit_length() (The Python Standard Library) (Python Software Foundation)
- chr() and ord() (Built-in Functions) (Python Software Foundation)
- Integer literals (The Python Language Reference) (Python Software Foundation)
- stat, Interpreting stat() results (file permission bits) (Python Software Foundation)
- CSS Color Module Level 4: the RGB hexadecimal notations (W3C CSS Working Group)
- enum.Flag (enum, Support for enumerations) (Python Software Foundation)
- Operator precedence (The Python Language Reference) (Python Software Foundation)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress