Python language fundamentals: identifiers, keywords, data types and type casting
Advertisement
Every Python program is built from the same small set of ideas: names that refer to values, and values that have a type. If you understand how names are formed, which words are reserved, what types exist and how to convert between them, the rest of the language falls into place. This post covers those fundamentals with examples that were run on a real interpreter (Python 3.9; results are the same on newer versions). It goes with the video lesson linked at the end.
Identifiers: the names you choose
An identifier is the name of a variable, function, class, module or any other object. The rules are strict:
- It may contain letters, digits and underscores, and must not start with a digit.
- It is case sensitive:
nameandNameare different identifiers. - It cannot be a reserved word (see the next section).
- It cannot contain spaces or symbols such as
$,-or@.
_x = 1; __y = 2; x1 = 3
print(_x, __y, x1) # 1 2 3
print("Name" == "name") # False: case matters
The names 2fast, my-var and my var are all invalid and give a SyntaxError.
Some conventions are not enforced but are followed by nearly all Python code: snake_case for variables and functions (total_price), PascalCase for classes (ShoppingCart) and UPPER_CASE for constants (MAX_SIZE). A name starting with one underscore (_cache) signals "internal use"; two leading underscores trigger name mangling inside classes; names with two on each side (__init__) are special methods that Python itself calls. Do not invent your own.
Reserved words (keywords)
Keywords have a fixed meaning in the language, so you can't use them as names. Python can list them for you:
import keyword
print(keyword.iskeyword("class"), keyword.iskeyword("Class")) # True False
print(keyword.kwlist[:12])
# ['False', 'None', 'True', '__peg_parser__', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue']
The list changes slightly between versions (the sample above is from 3.9), so use keyword.kwlist instead of memorising it. A few facts worth remembering: True, False and None are keywords with a capital letter, while all the others are lower case, which is why Class is allowed but class is not. print and len are not keywords; they are built-in functions that you could overwrite by mistake (print = 5 is legal and breaks printing, so never do it).
The built-in data types
Python is dynamically typed: you do not declare a type; the value carries it, and type() tells you.
for v in [42, 3.14, 2+3j, True, "hi", b"hi", bytearray(b"hi"), range(3), [1], (1,), {1}, frozenset({1}), {"a": 1}, None]:
print(type(v).__name__, end=" ")
# int float complex bool str bytes bytearray range list tuple set frozenset dict NoneType
| Type | Example | Mutable? | Notes |
|---|---|---|---|
int |
42 |
no | Unlimited size: 10**20 works |
float |
3.14 |
no | Binary floating point, about 15 digits |
complex |
2+3j |
no | Real and imaginary parts |
bool |
True |
no | A subclass of int (True == 1) |
str |
"hi" |
no | Text, a sequence of Unicode characters |
bytes |
b"hi" |
no | A sequence of byte values 0 to 255 |
bytearray |
bytearray(b"hi") |
yes | Like bytes, but changeable |
range |
range(3) |
no | A lazy sequence of integers |
list |
[1, 2] |
yes | Ordered collection |
tuple |
(1, 2) |
no | Ordered, fixed collection |
set |
{1, 2} |
yes | Unique items, no order |
frozenset |
frozenset({1}) |
no | An unchangeable set |
dict |
{"a": 1} |
yes | Key-value pairs |
NoneType |
None |
no | The single "no value" object |
"Mutable" means the object can change in place. This matters when two names refer to the same object, as the Python cheat sheet shows.
Numbers and number systems
Integers can be written in several bases. Python converts them all to the same int:
print(10, 0b1010, 0o12, 0xA, 1_000_000, 1e3) # 10 10 10 10 1000000 1000.0
print(bin(10), oct(10), hex(255)) # 0b1010 0o12 0xff
print(int("1010", 2), int("ff", 16)) # 10 255
0b is binary, 0o octal and 0x hexadecimal. Underscores in numbers (1_000_000) are ignored and exist only for readability. A float written with e (1e3) is always a float.
Floating-point numbers are stored in binary, so some decimals can't be exact:
print(0.1 + 0.2) # 0.30000000000000004
import math
print(math.isclose(0.1 + 0.2, 0.3)) # True
Compare floats with math.isclose, and use the decimal module for money.
bool
bool has two values, True and False. Every object has a truth value: zero, empty containers, "" and None are false; nearly everything else is true.
print(bool(""), bool(" ")) # False True (a space is not empty)
str, bytes and bytearray
A str holds text. bytes holds raw bytes and is immutable; bytearray is its changeable version.
print(bytes([72, 105]), bytearray(b"hi") + b"!", list(b"Hi"))
# b'Hi' bytearray(b'hi!') [72, 105]
b = bytearray(b"hi"); b[0] = 72; print(b) # bytearray(b'Hi')
try:
bytes(b"hi")[0] = 1
except TypeError as e:
print(e) # 'bytes' object does not support item assignment
Text becomes bytes by encoding ("é".encode("utf-8")) and bytes become text by decoding. The string post goes further.
range
range(start, stop, step) produces integers lazily, so range(1_000_000) takes no memory for the numbers.
print(list(range(2, 10, 3)), list(range(5, 0, -2)), range(10)[3], len(range(0, 10, 3)))
# [2, 5, 8] [5, 3, 1] 3 4
The stop value is never included.
list, tuple, set, frozenset and dict
These are the collection types. A list is ordered and changeable, a tuple ordered and fixed, a set unordered with unique members, and a dict maps keys to values. Each has its own post: tuple and set, and the cheat sheet covers lists and dictionaries.
None
None is the only value of NoneType. It means "no value here" and is what a function returns when it has no return. Test for it with is:
print(None is None, type(None)) # True <class 'NoneType'>
Type casting (conversion)
Python does not convert between unrelated types silently, so you do it with the type's name as a function.
print(int("42"), int(3.9), int(-3.9), float("2.5"), str(7) + "!") # 42 3 -3 2.5 7!
print(complex(1, 2), bool(""), int("ff", 16)) # (1+2j) False 255
Notes:
int(3.9)truncates toward zero (soint(-3.9)is-3); useround()to round.int("3.5")fails; the string must be a whole number. Go throughfloatfirst.- Conversion can fail, and you should be ready to handle it:
try:
int("3.5")
except ValueError as e:
print(e) # invalid literal for int() with base 10: '3.5'
- You can't convert a
complextointorfloat. str(x)works for everything, andlist("abc")splits a string into characters.
Remember that input() always returns a string, so int(input("Age: ")) is the usual pattern.
Escape characters
Inside a normal string, a backslash starts an escape sequence: \n newline, \t tab, \\ backslash, \' and \" quotes, and é a Unicode character. A raw string (r"...") leaves backslashes alone, which is handy for file paths and regular expressions.
print("a\tb", 'it\'s', "line1\nline2", r"raw\n", "é", len("é"))
# a b it's line1
# line2 raw\n é 1
Constants
Python has no real constants. By convention, a name in capitals means "do not change":
PI = 3.14159
Python won't stop you from reassigning it, but other programmers will know the intent. The standard library has real constants such as math.pi and math.e.
Multiple assignment and swapping
a, b = 1, 2
a, b = b, a
print(a, b) # 2 1
The right side is evaluated first as a tuple, so no temporary variable is needed.
Common mistakes
- Starting a name with a digit or using a hyphen.
- Using a keyword (or a built-in such as
list) as a variable name. - Assuming
input()returns a number. - Comparing floats with
==. - Forgetting that
int()truncates. - Treating
bool("False")as false: any non-empty string is true.
Where to go next
Watch the matching video: Episode 4: identifiers, keywords and data types. Then move on to operators, which combine these values, and practise with the Python cheat sheet and the interview questions. The whole path is laid out in the guide to the Python video course.