Skip to content

Python Fundamentals

This content is for Python. Switch to the latest version for up-to-date documentation.

Python is a dynamic, interpreted (bytecode-compiled) language.

There are no type declarations of variables, parameters, functions, or methods in source code. This makes the code short and flexible, and you lose the compile-time type checking of the source code. Python tracks the types of all values at runtime and flags code that does not make sense as it runs.

Python source files use the “.py” extension and are called “modules.” With a Python module hello.py, the easiest way to run it is with the shell command “python hello.py Alice” which calls the Python interpreter to execute the code in hello.py, passing it the command line argument “Alice”.

Here’s a very simple hello.py program:

# import modules used here -- sys is a very standard one
import sys
# Gather our code in a main() function
def main():
print('Hello', sys.argv[1])
# Command line args are in sys.argv[1], sys.argv[2] ...
# sys.argv[0] is the script name itself and can be ignored
# Standard boilerplate to call the main() function to begin
# the program.
if __name__ == '__main__':
main()

Running this program from the command line looks like:

Terminal window
python3 hello.py Ner

You can also use the interactive REPL by running python3 and typing expressions line by line. Press Ctrl+D (macOS/Linux) or Ctrl+Z then Enter (Windows) to exit.

  • Variables are created by assignment; the type is inferred at runtime.
  • Common built-in types: int, float, bool, str, list, tuple, set, dict, NoneType.
  • Use type(x) to inspect a value’s type.
x = 42 # int
y = 3.14 # float
flag = True # bool
name = "Ner" # str
data = None # NoneType (represents “no value”)
print(type(x), type(y), type(flag), type(name), type(data))

Numbers support standard arithmetic, integer division (//), modulo (%), and exponentiation (**).

7 // 3 # 2
7 % 3 # 1
2 ** 5 # 32

Comparison and boolean operators: == != < <= > >= and and or not. Remember that == compares values, while is compares object identity.

Functions in Python are defined like this:

# Defines a "repeat" function that takes 2 arguments.
def repeat(s, exclaim):
"""
Returns the string 's' repeated 3 times.
If exclaim is true, add exclamation marks.
"""
result = s + s + s # can also use "s * 3" which is faster (Why?)
if exclaim:
result = result + '!!!'
return result
def main():
print(repeat('Yay', False)) ## YayYayYay
print(repeat('Woo Hoo', True)) ## Woo HooWoo HooWoo Hoo!!!

More function features:

def greet(name="world"): # default argument
return f"Hello, {name}!"
def add(*nums): # variable positional args
return sum(nums)
def configure(**options): # variable keyword args
return options
def area(w: float, h: float) -> float: # type hints (annotations)
return w * h
print(greet()) # Hello, world!
print(add(1, 2, 3)) # 6
print(configure(debug=True)) # {'debug': True}

Docstrings (triple-quoted strings right after def) are the canonical place to document functions and are accessible via help(func).

One unusual Python feature is that the whitespace indentation of a piece of code affects its meaning. A logical block of statements such as the ones that make up a function should all have the same indentation, set in from the indentation of their parent function or “if” or whatever. If one of the lines in a group has a different indentation, it is flagged as a syntax error.

Python’s use of whitespace feels a little strange at first, but it’s logical and I found I got used to it very quickly. Avoid using TABs as they greatly complicate the indentation scheme (not to mention TABs may mean different things on different platforms). Set your editor to insert spaces instead of TABs for Python code.

Strings are sequences of Unicode characters.

  • Literals: single quotes '...', double quotes "...", or triple quotes for multi-line '''...''' / """...""".
  • Escape sequences: \n newline, \t tab, \uXXXX Unicode, or use raw strings r"C:\\path" to avoid escapes.
  • Concatenate with +, repeat with *, and interpolate with f-strings f"...{expr}...".
s = "hello"
t = 'world'
u = s + ' ' + t # "hello world"
v = s * 3 # "hellohellohello"
name = "Ner"
msg = f"Hi {name}!" # f-string

Indexing, slicing, and common methods:

text = "Python"
text[0] # 'P'
text[-1] # 'n'
text[1:4] # 'yth'
text[::-1] # 'nohtyP' (reversed)
text.lower() # 'python'
text.upper() # 'PYTHON'
" spaced ".strip() # 'spaced'
"a,b,c".split(',') # ['a', 'b', 'c']
"-".join(["a","b"]) # 'a-b'

Lists are ordered, mutable collections.

nums = [1, 2, 3]
nums.append(4) # [1, 2, 3, 4]
nums.extend([5, 6]) # [1, 2, 3, 4, 5, 6]
nums.insert(0, 0) # [0, 1, 2, 3, 4, 5, 6]
nums.remove(3) # removes first 3
last = nums.pop() # pops 6
nums[1:4] # slice [1, 2, 3]

Sorting and safe copies:

data = [3, 1, 2]
data.sort() # in-place -> [1, 2, 3]
sorted(data, reverse=True) # returns new list -> [3, 2, 1]

List comprehensions are concise ways to build lists:

squares = [n*n for n in range(5)] # [0, 1, 4, 9, 16]
evens = [n for n in range(10) if n % 2 == 0] # [0, 2, 4, 6, 8]

Looping patterns:

for i, value in enumerate(["a","b","c"], start=1):
print(i, value)

Dictionaries map keys to values and are very fast for lookups.

person = {"name": "Ada", "age": 36}
person["job"] = "Engineer"
person["age"] += 1
person.get("missing") # None (safe)
person.get("missing", 0) # default value 0
for k, v in person.items():
print(k, v)

Dictionary comprehension:

square_map = {n: n*n for n in range(5)} # {0:0, 1:1, 2:4, 3:9, 4:16}

Keys must be hashable (immutable types like str, int, tuple).

# Tuple: ordered, immutable
pt = (10, 20)
x, y = pt # unpacking
# Set: unordered collection of unique items
colors = {"red", "green", "blue", "red"} # {'red', 'green', 'blue'}
colors.add("yellow")
primary = {"red", "green", "blue"}
warm = {"red", "yellow"}
primary & warm # intersection -> {'red'}
primary | warm # union -> {'red', 'green', 'blue', 'yellow'}
x = 7
if x < 0:
print("negative")
elif x == 0:
print("zero")
else:
print("positive")
for n in range(3):
if n == 1:
continue
print(n)
count = 3
while count > 0:
print(count)
count -= 1

Truthiness: empty collections, 0, and None are “falsy”; most other values are “truthy”.

# list
cubes = [n**3 for n in range(5)]
# dict
index = {word: i for i, word in enumerate(["a","b","c"])}
# set
unique_lens = {len(w) for w in ["aa","b","ccc","aa"]} # {1, 2, 3}
try:
value = int("42")
except ValueError as e:
print("Not a number:", e)
else:
print("Converted successfully")
finally:
print("Always runs")
# Raising your own
def sqrt(x):
if x < 0:
raise ValueError("x must be non-negative")
return x ** 0.5
# Reading a text file
with open("notes.txt", "r", encoding="utf-8") as f:
text = f.read()
# Writing (overwrites)
with open("out.txt", "w", encoding="utf-8") as f:
f.write("Hello, file!\n")
# Append
with open("out.txt", "a", encoding="utf-8") as f:
f.write("More text\n")
  • Follow PEP 8 (indent with 4 spaces, snake_case for variables/functions, CapWords for classes).
  • Prefer f-strings for formatting.
  • Use list/dict/set comprehensions for concise transformations.
  • Handle errors explicitly with try/except.
  • Keep functions small and focused; document with docstrings.

Ready to apply what you learned? Try these: Python Practice Exercises

Built with passion by Ngineer Lab