Python
Python is a popular general-purpose scripting language that is especially suited to web development.
All examples are based on Python 3.10.
Resources:
How to start
After installing Python, you can create a file with .py
extension and run it with python
command.
print("Hello, world")
Topics
- Variables
- Built-in types
- Operators
- Type hinting
- String
- Collections
- Conditional statements
- Loops
- Functions
- Classes
- Metaclasses
- Mixins
- Dataclasses
- Class Decorators
- Error Handling
- Modules
- Generators
- Iterators
Variables
# simple declaration
message = "Hello, world"
# multiple assignment
a = 10
b = 20
c = 30
# type hinting
age: int = 30
name: str = "Python"
Built-in types
# None
x = None
# Boolean
y = True
z = False
# Integer
a = 10
b = 100
c = -10
# Float
d = 10.5
e = 10.0
f = -10.0
# String
g = "Hello, world"
h = 'Hello, world'
i = """Hello,
world"""
# List
l = [1, 2, 3]
# Tuple
t = (1, 2, 3)
# Set
s = {1, 2, 3}
# Dictionary
d = {"a": 1, "b": 2, "c": 3}
# Range
r = range(1, 10)
Operators
# arithmetic operators
a = 10 + 5 # 15
b = 10 - 5 # 5
c = 10 * 5 # 50
d = 10 / 5 # 2
e = 10 % 3 # 1
# assignment operators
f = 10
f += 5 # 15
f -= 5 # 10
f *= 5 # 50
f /= 5 # 10
f %= 3 # 1
# comparison operators
g = 10 == 10 # True
h = 10 != 5 # True
i = 10 > 5 # True
j = 10 < 5 # False
k = 10 >= 10 # True
l = 10 <= 5 # False
# logical operators
m = True and True # True
n = True or False # True
o = not True # False
# increment and decrement operators
p = 10
p++ # 11
p-- # 10
# concatenation
q = "Hello" + " " + "world" # Hello world
# null coalescing
r = None ?? "no value" # no value
# null coalescing assignment
s = None
s ??= "no value" # no value
# spaceship operator
t = 10 <=> 5 # 1
u = 5 <=> 10 # -1
v = 10 <=> 10 # 0
# ternary
w = True ? "show if true" : "show if false" # show if true
# shorthand ternary
x = False ? "first" : "second" # first
y = 5 ? "first" : "second" # second
z = 5 ?: 0 # 5
# assignment
a = 10
a = 20 # a = 20
Type hinting
Python type hinting, introduced in Python 3.5 and enhanced in subsequent versions, is a way to indicate the expected types of variables, function parameters, and return values in your code.
# basic syntax
def greet(name: str) -> str:
return f"Hello, {name}"
age: int = 30
# common types
from typing import List, Dict, Tuple, Optional
typed_list: List[int] = [1, 2, 3]
typed_dict: Dict[str, int] = {"a": 1, "b": 2, "c": 3}
typed_tuple: Tuple[int, str, float] = (1, "hello", 3.14)
typed_optional: Optional[str] = "hello"
# user defined types
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"Hello, {self.name}!")
def get_person_age(person: Person) -> int:
return person.age
# union types
from typing import Union
def print_id(id: Union[int, str]):
print(f"ID: {id}")
print_id(1)
print_id("10")
# any type
from typing import Any
def process_data(data: Any) -> None:
pass
# type aliases
from typing import List, Tuple
Vector = List[float]
Matrix = List[Vector]
def scale_matrix(matrix: Matrix, factor: float) -> Matrix:
# callable types
from typing import Callable
def apply_operation(x: int, operation: Callable[[int], int]) -> int:
return operation(x)
# generic types
from typing import TypeVar, List
T = TypeVar('T')
def first(l: List[T]) -> T:
return l[0]
# final variables (Python 3.8+)
from typing import Final
MAX_SIZE: Final = 100
# Literal Types (Python 3.8+)
from typing import Literal
def move(direction: Literal['left', 'right', 'up', 'down']) -> None:
pass
String
# basic declaration
string = "Hello, world"
# [+] operator
print("hello" + " " + "world") # hello world
# [*] operator
print("hello" * 3) # hellohellohello
# [in] operator
print("hello" in "hello world") # True
# [not in] operator
print("hello" not in "hello world") # False
# built-in string functions
print(len("hello")) # 5
print(str.upper("hello")) # HELLO
print(str.lower("HELLO")) # hello
print(str.capitalize("hello")) # Hello
print(str.title("hello")) # Hello
print(str.count("hello", "l")) # 2
print(str.find("hello", "l")) # 2
print(str.rfind("hello", "l")) # 5
print(str.index("hello", "l")) # 2
print(str.rindex("hello", "l")) # 5
print(str.replace("hello", "l", "x")) # hexxo
# build-in string methods
string = "hello world"
print(string.startswith("hello")) # True
print(string.endswith("world")) # True
print(string.upper()) # HELLO WORLD
print(string.lower()) # hello world
# string slicing
s = "hello world"
print(s[0]) # h
print(s[1:4]) # ell
print(s[1:]) # ello world
# string interpolation
carModel = "Toyota"
carYear = 2022
print(f"My {carModel} is {carYear}") # My Toyota is 2022
Collections
Arrays: are a fixed-size, ordered collection of elements of the same type.
from array import array
# array
my_array = array('i', [1, 2, 3, 4, 5])
my_array.reverse()
my_array.append(6)
my_array.extend([7, 8, 9])
print(type(my_array))
Lists: are a dynamic-size, ordered collection of elements of the same type.
# list
my_list = [1, 2, 3, 4, 5]
my_list.reverse()
my_list.append(6)
my_list.extend([7, 8, 9])
print(type(my_list))
Tuples: are a fixed-size, ordered collection of elements of the same type.
# tuple
my_tuple = (1, 2, 3, 4, 5)
my_tuple.count(2) # 2
my_tuple.index(2) # 1
Sets: are an unordered collection of unique elements.
# set
my_set = {1, 2, 3, 3, 4, 4, 5, 5, 5}
my_set.add(6)
my_set.remove(2)
my_set.union({6, 7, 8})
print(type(my_set))
Dictionaries: are a collection of key-value pairs.
# dictionary
my_dict = {"a": 1, "b": 2, "c": 3}
my_dict.update({"d": 4, "e": 5})
my_dict.pop("b")
my_dict.clear()
print(type(my_dict))
Conditional statements
# if statement
if x > 10:
print("x is greater than 10")
# if-else statement
if x > 10:
print("x is greater than 10")
else:
print("x is less than or equal to 10")
# if-elif-else statement
if x > 10:
print("x is greater than 10")
elif x < 10:
print("x is less than 10")
else:
print("x is equal to 10")
# short hand if
if a > b: print("a is greater than b")
# short hand if-else
print("a is greater than b") if a > b else print("a is less than or equal to b")
# and
if a > b and b > c:
print("a is greater than b and b is greater than c")
# or
if a > b or b > c:
print("a is greater than b or b is greater than c")
# not
if not a > b:
print("a is not greater than b")
# pass statement
if a > b:
pass
Match and Case Statements
x = 10
match x:
case 1:
print("x is 1")
case 2:
print("x is 2")
case _:
print("x is neither 1 nor 2")
Loops
# for loop
for i in range(1, 10):
print(i)
# while loop
i = 1
while i <= 10:
print(i)
i += 1
# break statement
i = 1
while i <= 10:
print(i)
if i == 5:
break
i += 1
# continue statement
i = 1
while i <= 10:
if i == 5:
continue
print(i)
i += 1
List Comprehension: is a concise way to create lists based on existing lists.
numbers = [1, 2, 3, 4, 5]
squared_numbers = [x**2 for x in numbers]
print(squared_numbers)
Functions
# basic declaration
def greet(name):
print(f"Hello, {name}!")
# default parameter
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Python") # Hello, Python!
greet("Bob", "Hi") # Hi, Bob!
greet(name="Python", greeting="Hi") # Hi, Python!
# variable length argument list
def sum(*numbers):
total = 0
for number in numbers:
total += number
return total
# keyword arguments
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
# *args and **kwargs
def print_args(*args, **kwargs):
for arg in args:
print(arg)
for key, value in kwargs.items():
print(f"{key}: {value}")
print_args(1, 2, 3, name="Python", age=30)
Lambda Functions: are anonymous functions that can be used in place of a function name.
# lambda function
multiply = lambda x, y: x * y
print(multiply(2, 3)) # 6
# lambda function with default parameter
add = lambda x, y=0: x + y
print(add(2, 3)) # 5
Classes
# basic class
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# methods
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"Hello, {self.name}!")
def get_age(self):
return self.age
# class attributes
class Car:
wheels = 4 # Class attribute
def __init__(self, make):
self.make = make # Instance attribute
# class methods
class Car:
wheels = 4 # Class attribute
def __init__(self, make):
self.make = make # Instance attribute
@classmethod
def get_wheels(cls):
return cls.wheels
# static methods
class Calc:
@staticmethod
def add(x, y):
return x + y
@staticmethod
def subtract(x, y):
return x - y
@staticmethod
def multiply(x, y):
return x * y
@staticmethod
def divide(x, y):
return x / y
# getter and setter
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@property
def name(self):
return self._name.upper()
@name.setter
def name(self, value):
self._name = value
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value > 0:
self._age = value
else:
raise ValueError("Age must be a positive number")
person = Person("Python", 30)
print(person.name)
person.name = "Bob"
print(person.name)
#encapsulation
class BankAccount:
def __init__(self, balance):
self.__balance = balance # "Private" attribute
def deposit(self, amount):
self.__balance += amount
Magic Methods: are special methods that are called automatically by the Python interpreter.
# magic methods
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self): # convert to string
return f"{self.title} by {self.author}"
def __eq__(self, other): # check equality
return self.title == other.title and self.author == other.author
person = Person("Python", 30)
print(person)
Inheritance: is a mechanism that allows a class to inherit the properties and methods of another class.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"Hello, {self.name}!")
class Hero(Person):
def __init__(self, name, age, power):
super().__init__(name, age)
self.power = power
def fight(self):
print(f"{self.name} is fighting with {self.power}!")
Metaclasses
Metaclasses are classes that define the behavior of other classes. They are used to customize the behavior of classes at runtime.
# metaclass
class MetaclassExample(type):
def __new__(cls, name, bases, attrs):
print(f"Creating a new class: {name}")
return super().__new__(cls, name, bases, attrs)
class Example(metaclass=MetaclassExample): pass
Example # Output: Creating a new class: Example
Mixins
Mixins are a way to share code between classes. They allow you to define reusable functionality that can be included in multiple classes.
# mixin
class Printable:
def print(self):
print(self)
class Person(Printable):
def __init__(self, name):
self.name = name
person = Person("Python")
person.print() # Output: Person('Python')
import json
class SerializeMixin:
def serialize(self):
return json.dumps(self.__dict__)
class SaveableMixin:
def save(self):
# Code to save object to database
pass
class User(SerializeMixin, SaveableMixin):
def __init__(self, name, email):
self.name = name
self.email = email
user = User("Python", "python@example.com")
print(user.serialize())
user.save()
Dataclasses
Dataclasses are a special type of class that automatically generate methods for accessing and modifying the attributes of the class.
# basic usage
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
p = Point(1, 2)
print(p)
# default values
@dataclass
class Person:
name: str
age: int = 30
# post-init processing
@dataclass
class Circle:
radius: float
area: float = 0.0
def __post_init__(self):
self.area = 3.14 * self.radius ** 2
# immutable dataclasses
@dataclass(frozen=True)
class ImmutablePoint:
x: int
y: int
# inheritance
@dataclass
class Animal:
name: str
@dataclass
class Dog(Animal):
breed: str
# field options
from dataclasses import dataclass, field
import random
@dataclass
class Point:
id: int = field(init=False, default_factory=lambda: Point.random_id())
x: int
y: int
@staticmethod
def random_id():
return random.randint(1, 100)
p = Point(1, 2)
p2 = Point(x=3, y=4)
print(p)
print(p2)
# comparison
@dataclass(order=True)
class Person:
name: str = field(compare=False)
age: int
# conversion to dictionary
@dataclass
class Point:
x: int
y: int
p = Point(1, 2)
print(asdict(p))
# slots
@dataclass(slots=True)
class Efficient:
x: int
y: int
Class Decorators
Class decorators are a way to modify the behavior of a class at runtime.
def add_greeting(cls):
cls.greet = lambda self: print(f"Hello, {self.name}!")
return cls
@add_greeting
class Person:
def __init__(self, name):
self.name = name
person = Person("Python")
person.greet()
Error Handling
# example of a error handling function
def basic_error_handling(x, y):
try:
result = x / y
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Division by zero")
except Exception as e:
print(f"Error: {e}")
# multiple exceptions in one block
def multiple_exceptions(x, y):
try:
file = open("file.txt", "r")
age = int(input("Enter your age: "))
except (FileNotFoundError, ValueError) as Error:
print(f"Error: {Error}")
# try-except-else-finally block
def complete_error_handling():
try:
file = open("example.txt", "w")
file.write("Hello, world!")
except:
print("Error: Unable to open file")
else:
print("File opened successfully")
finally:
file.close()
print("File closed")
# custom exception class
class AgeError(Exception):
def __init__(self, message="Invalid age entered"):
self.message = message
super().__init__(self.message)
# using custom exception
def verify_age(age):
try:
age = int(age)
if age < 0 or age > 150:
raise AgeError("Age must be between 0 and 150")
return f"Valid age: {age}"
except ValueError:
return "Please enter a numeric value"
except AgeError as e:
return str(e)
Modules
# importing a module
import math
# importing specific functions from a module
from math import sqrt, sin, cos
# importing all functions from a module
from math import *
# importing a module with an alias
import math as m
# importing a module and using it in the code
import math
print(math.sqrt(16)) # 4
print(sqrt(16)) # 4.0
print(m.sqrt(16)) # 4.0
# importing a module from a different directory
import sys
sys.path.append("path/to/directory")
# importing a module from a different directory with an alias
import sys
sys.path.append("path/to/directory")
from my_module import my_function
Custom modules
calc.py
def add(x, y):
return x + y
def subtract(x, y):
return x - y
def multiply(x, y):
return x * y
def divide(x, y):
return x / y
main.py
import calc
print(calc.add(2, 3)) # 5
print(calc.subtract(5, 2)) # 3
print(calc.multiply(4, 6)) # 24
print(calc.divide(10, 2)) # 5.0
Generators
Generators are a type of iterable, similar to lists or tuples, but with a key difference: they donβt store all the values in memory at once. Instead, they generate the values on the fly as they are needed.
# basic example of generator
def gen():
yield 1
yield 2
yield 3
print(list(gen()))
# fibonacci sequence
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib = fibonacci()
for _ in range(6):
print(next(fib))
Iterators
Iterators are objects that allow you to iterate over a sequence of values, one at a time. They are used in a for
loop to loop over a sequence of values.
# built-in iterator
my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list) # Creating an iterator
# using the iterator
print(next(my_iterator)) # Output: 1
print(next(my_iterator)) # Output: 2
print(next(my_iterator)) # Output: 3
# custom iterator
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
else:
self.current -= 1
return self.current + 1
# create an iterator object
countdown = CountDown(5)
# using the iterator
for num in countdown:
print(num)
Keywords
Keyword | Description |
---|---|
False | Boolean value representing false. |
None | Represents the absence of a value. |
True | Boolean value representing true. |
and | Logical operator for conjunction. |
as | Used to create an alias in imports or exceptions. |
assert | For debugging, tests a condition. |
async | Defines asynchronous functions. |
await | Used with async to pause and resume execution. |
break | Exits out of a loop. |
class | Defines a new class. |
continue | Skips the rest of the current loop iteration. |
def | Defines a function. |
del | Deletes an object. |
elif | Else if; used in conditional statements. |
else | Defines the alternative branch of a condition. |
except | Catches exceptions in a try block. |
finally | Executes code after try -except blocks, regardless of outcome. |
for | Defines a loop. |
from | Imports specific parts of a module. |
global | Declares a global variable. |
if | Starts a conditional statement. |
import | Imports a module or package. |
in | Checks if a value exists in a sequence. |
is | Tests object identity. |
lambda | Defines an anonymous function. |
nonlocal | Declares a non-local variable in nested functions. |
not | Logical operator for negation. |
or | Logical operator for disjunction. |
pass | A null statement; does nothing. |
raise | Raises an exception. |
return | Returns a value from a function. |
try | Tests code for errors. |
while | Defines a while loop. |
with | Simplifies exception handling and resource management. |
yield | Pauses a function and returns an intermediate result. |