---
website: https://www.python.org
obj: concept
mime: "text/python"
extension: "py"
rev: 2024-02-19
---

# Python
Python is an interpreted programming language.

## Usage
Python is a interpreted language, so you will need a python interpreter. You can code python interactively or run a script with:
```shell
python3 [script.py] [args]
```

Or you can prefix your script with a shebang:
```python
#!/usr/bin/python3
print("Hello World")
```

## Syntax
Python hello world:
```python
print("Hello World")
```

### Comments
Python lets you do comments with the `#` sign.
```python
# This is a comment
```

### Variables
You can define variables like this:
```python
myvar = 3
# define multiple
a, b = 5, 9
```

### Data Types
In Python, there are several built-in data types. Here are some examples:

#### Numeric Types
```python
# Integer
my_int = 10

# Float
my_float = 3.14
```

#### String
```python
my_string = "Hello, world!"
```

#### Boolean
```python
my_bool = True
```

#### List
```python
my_list = [1, 2, 3, 4, 5]
```

#### Tuple
```python
my_tuple = (1, 2, 3)
```

#### Dictionary
```python
my_dict = {'name': 'John', 'age': 30}
```

#### Set
```python
my_set = {1, 2, 3}
```

#### Explicit typing
Explicit typing refers to the practice of explicitly declaring the data type of variables, parameters, or return values in a programming language. While Python is dynamically typed, meaning you don't have to declare the data type of variables explicitly, there are situations where you might want to provide type hints for clarity and documentation purposes, especially in large codebases or when working in a team.

Python 3.5 introduced type hints as a way to provide optional type information. Type hints are annotations that indicate the expected types of variables, function parameters, and return values. They do not affect the runtime behavior of the program but can be used by static analysis tools and IDEs to perform type checking.
```python
def add(x: int, y: int) -> int:
	"""Add two integers and return the result."""
	return x + y
```

In this example, `x: int` and `y: int` indicate that `x` and `y` should be integers, and `-> int` indicates that the function returns an integer.

Type hints are not enforced by the Python interpreter, so you can still pass arguments of different types to a function that has type hints. However, tools like `mypy` can be used to perform static type checking and catch type errors at compile time.

### if statements
In Python, `if` statements are used for conditional execution.

```python
x = 10

if x > 5:
	print("x is greater than 5")
```

You can also include `elif` (short for "else if") and `else` clauses for more complex conditions:
```python
x = 10

if x > 10:
	print("x is greater than 10")
elif x == 10:
	print("x is equal to 10")
else:
	print("x is less than 10")
```

You can also use logical operators such as `and`, `or`, and `not` to combine conditions:
```python
x = 5
y = 3

if x > 0 and y > 0:
	print("Both x and y are positive")
elif x > 0 or y > 0:
	print("At least one of x or y is positive")
else:
	print("Both x and y are non-positive")
```

Remember to use proper indentation to define blocks of code within `if`, `elif`, and `else` statements in Python.

### for statements
In Python, `for` loops are used to iterate over sequences like lists, tuples, strings, or other iterable objects. Here's a basic example:
```python
# Iterate over a list
my_list = [1, 2, 3, 4, 5]
for item in my_list:
	print(item)
```

You can also use the `range()` function to generate a sequence of numbers to iterate over:
```python
# Iterate over a range of numbers
for i in range(5):
	print(i)
```

You can iterate over other iterable objects as well, such as strings:
```python
# Iterate over a string
my_string = "Hello"
for char in my_string:
	print(char)
```

### break and continue statements
In Python, `break` and `continue` are used to control the flow of loops.

#### break statement
The `break` statement is used to exit a loop prematurely. Here's an example:
```python
# Break the loop when x reaches 5
x = 0
while True:
	print(x)
	x += 1
	if x == 5:
		break
```

In this example, the loop will iterate indefinitely until `x` equals 5. Once `x` reaches 5, the `break` statement is executed, and the loop terminates.

#### continue statement
The `continue` statement is used to skip the rest of the code inside a loop for the current iteration and proceed to the next iteration. Here's an example:
```python
# Skip even numbers and print odd numbers
for i in range(10):
	if i % 2 == 0:
		continue
	print(i)
```

In this example, when `i` is an even number, the `continue` statement is executed, and the loop moves to the next iteration without executing the `print(i)` statement. As a result, only odd numbers are printed.

### pass statement
In Python, the `pass` statement is a null operation. It is used when a statement is syntactically required but you do not want to execute any code. It acts as a placeholder. Here's an example:
```python
if x < 10:
	pass  # This block does nothing
else:
	print("x is greater than or equal to 10")
```

### match statement
The `match` statement was introduced in Python 3.10 as a replacement for the `switch` statement. It provides a more flexible and readable way to perform pattern matching. Here's an example:
```python
def weekday_name(day_num):
	match day_num:
		case 1:
			return "Monday"
		case 2:
			return "Tuesday"
		case 3:
			return "Wednesday"
		case 4:
			return "Thursday"
		case 5:
			return "Friday"
		case 6 | 7:
			return "Weekend"
		case _:
			return "Invalid day" 

print(weekday_name(3))  # Output: Wednesday
print(weekday_name(6))  # Output: Weekend
print(weekday_name(9))  # Output: Invalid day
```

In this example, the `match` statement takes an expression (`day_num`) and matches it against several patterns using `case` clauses. The `_` acts as a wildcard pattern that matches any value not covered by previous cases.

The `|` operator allows you to match multiple patterns together, like `case 6 | 7:` which matches either 6 or 7.

### Functions
In Python, functions are blocks of reusable code that perform a specific task. They allow you to break down your program into smaller, manageable pieces.

#### Defining a Function
You can define a function using the `def` keyword followed by the function name and parentheses containing any parameters the function takes. The function body is indented below the function definition. Here's an example:
```python
def greet(name):
	"""This function greets the person with the given name."""
	print("Hello, " + name + "!")
```

In this example, `greet` is the function name, and it takes one parameter `name`.

#### Calling a Function
To call a function, simply use the function name followed by parentheses containing any required arguments. Here's how you call the `greet` function defined above:
```python
greet("Alice")
```

Ordering of the function arguments matters, unless you use explicit named arguments:
```python
def eat(food, amount):
	print(f"I eat {amount} {food}")

# Ordering matters
eat("Pizza", "3") # Output: I eat 3 Pizza
eat("3", "Pizza") # Output: I eat Pizza 3

# Named arguments
# Improved readability
eat(food="Pizza", amount="3") # Output: I eat 3 Pizza
# Ordering does not matter
eat(amount="3", food="Pizza") # Output: I eat 3 Pizza
```

#### Returning Values
Functions can also return values using the `return` keyword. Here's an example:
```python
def add(a, b):
	"""This function adds two numbers."""
	return a + b
```

You can capture the returned value by assigning it to a variable or use it directly. Here's how you can use the `add` function:
```python
result = add(3, 5)
print(result)  # Output: 8
```

#### Default Parameters
You can provide default values for parameters in a function. If a parameter is not provided when calling the function, it will use the default value. Here's an example:

```python
def greet(name="World"):
	"""This function greets the person with the given name."""
	print("Hello, " + name + "!")
```

You can call this function with or without an argument:
```python
greet() # Output: Hello, World!
greet("Alice")  # Output: Hello, Alice!
```

### Lambda expressions
Lambda expressions, also known as lambda functions or anonymous functions, are a way to create small, unnamed functions in Python. They are defined using the `lambda` keyword, which is followed by a list of parameters, a colon, and an expression. Lambda functions can take any number of arguments but can only have one expression. They are typically used when you need a simple function for a short period of time and don't want to define a full-fledged function using the `def` keyword.

Here's the basic syntax of a lambda expression:
```python
lambda arguments: expression
```

Here's an example of a lambda function that takes two arguments and returns their sum:
```python
add = lambda x, y: x + y
```

You can then call this lambda function like a regular function:
```python
result = add(3, 5)
print(result)  # Output: 8
```

Lambda functions are often used in conjunction with built-in functions like `map()`, `filter()`, and `reduce()` to perform operations on iterables.

For example, you can use a lambda function with `map()` to apply a function to each element of a list:
```python
numbers = [1, 2, 3, 4, 5]
squared = map(lambda x: x**2, numbers)
print(list(squared))  # Output: [1, 4, 9, 16, 25]
```

### Documentation Comments
In Python, documentation comments, also known as docstrings, play a crucial role in explaining the purpose and usage of functions, classes, modules, and packages.

1. **Module-Level Docstrings**: These comments describe the module's purpose, its contents, and any important information for users. They appear at the beginning of the Python file, enclosed in triple quotes (''' or """). 
```python
'''This module provides utility functions for string manipulation.'''
```
2. **Function and Method Docstrings**: These comments explain the purpose, parameters, return values, and any exceptions raised by a function or method. They are placed immediately after the function or method definition, again enclosed in triple quotes.
```python
def greet(name):
	'''Greet the user by name.
	
	Args:
		name (str): The name of the user.
	
	Returns:
		str: A greeting message.'''
	return f"Hello, {name}!"
```
3. **Class Docstrings**: Similar to function docstrings, these comments describe the purpose and usage of a class. They are placed immediately after the class definition.
```python
class Calculator:
	'''A simple calculator class.'''
	
	def add(self, x, y):
		'''Add two numbers.'''
		return x + y
```

### Modules
In Python, a module is a file containing Python definitions and statements. The file name is the module name with the suffix `.py`. Modules are used to organize Python code into reusable units, facilitating better code management and sharing of functionality across different projects.

#### Creating Modules
To create a module, simply save your Python code in a file with a `.py` extension. For example, if you have a file named `my_module.py` containing the following code: 
```python
# my_module.py
def greet(name):
	return f"Hello, {name}!"
```

You can now import this module in another Python script using the `import` statement:
```python
import my_module

print(my_module.greet("Alice"))  # Output: Hello, Alice!
```

#### Module Attributes
Modules can contain functions, classes, and variables. These can be accessed using dot notation (`.`) after importing the module.
```python
# Accessing functions from a module
import math
print(math.sqrt(25))  # Output: 5.0
# Accessing variables from a module
print(math.pi)  # Output: 3.141592653589793
```

#### Module Search Path
When you import a module, Python searches for it in the directories listed in the `sys.path` variable. This includes the current directory, directories in the `PYTHONPATH` environment variable, and standard library directories.

#### Importing Specific Attributes
You can import specific attributes (functions, classes, or variables) from a module using the `from ... import ...` syntax.
```python
from math import sqrt
print(sqrt(25))  # Output: 5.0
```

This method allows you to use the imported attribute directly without qualifying it with the module name.

#### Aliasing Modules and Attributes
You can alias module names and attributes using the `as` keyword.
```python
import math as m
print(m.sqrt(25))  # Output: 5.0

from math import sqrt as square_root print(square_root(25))  # Output: 5.0
```

#### Executing Modules as Scripts
When you run a Python script directly, the code in the script is executed line by line. However, sometimes you may want certain code in a module to only run when the module is executed as a script, not when it's imported.

You can achieve this by adding the following block:
```python
if __name__ == "__main__":
	# Code to run when the module is executed directly
	print("This code runs only when the module is executed directly.")
```

#### Modules in Folders and Multiple Python Files
In larger projects, organizing code into modules within folders can enhance maintainability and scalability. Here's how you can structure your project:

1. **Creating a Folder Structure**: Organize your project files into folders based on functionality or modules.
2. **Module Files**: Each module can be contained within its own `.py` file within the appropriate folder. For example:
```
my_project/
├── main.py
├── utils/ 
│   ├── __init__.py 
│   ├── helper_functions.py 
│   └── constants.py 
├── models/ 
│   ├── __init__.py 
│   ├── user.py 
│   └── product.py
```
3. **`__init__.py` Files**: The presence of an `__init__.py` file in a folder indicates to Python that the folder should be treated as a package. This file can be empty or contain initialization code for the package.
4. **Importing Modules from Folders**: You can import modules from folders using dot notation (`.`) to traverse the folder structure.
```python
# Importing modules from folders
from utils.helper_functions import some_function
from models.user import User
```

### String Formatting
String formatting in Python refers to the process of creating strings with placeholders that are replaced by the values of variables or expressions. Python offers several methods for string formatting, each with its own advantages and use cases.

#### Using `%` Operator (Old Style Formatting)
The `%` operator is an older method of string formatting in Python. It uses a syntax similar to C's `printf` function.

```python
name = "Alice"
age = 30
formatted_string = "Name: %s, Age: %d" % (name, age)
print(formatted_string)  # Output: Name: Alice, Age: 30
```

#### Using `str.format()` Method
The `str.format()` method provides more flexibility and readability compared to the `%` operator.
```python
name = "Bob"
age = 25
formatted_string = "Name: {}, Age: {}".format(name, age)
print(formatted_string)  # Output: Name: Bob, Age: 25
```

You can also use named placeholders for better clarity:
```python
formatted_string = "Name: {name}, Age: {age}".format(name=name, age=age)
```

#### Using f-strings (Formatted String Literals)
f-strings provide a concise and intuitive way to format strings by embedding expressions directly inside string literals.

```python
name = "Charlie"
age = 35
formatted_string = f"Name: {name}, Age: {age}"
print(formatted_string)  # Output: Name: Charlie, Age: 35
```

f-strings support expressions and function calls:
```python
formatted_string = f"Name: {name.upper()}, Age in 5 years: {age + 5}"
```

### Errors and Exceptions
In Python, errors and exceptions are inevitable parts of programming. Errors occur when the Python interpreter encounters a problem while executing code, while exceptions are events that disrupt the normal flow of the program due to errors. Understanding how to handle errors and exceptions is crucial for writing robust and reliable Python code.

#### Syntax Errors
Syntax errors, also known as parsing errors, occur when the Python interpreter encounters invalid syntax in your code. These errors prevent the interpreter from executing the code.
```python
# Syntax Error: Missing colon in the if statement
if x == 5
	print("x is 5")
```

#### Exceptions
Exceptions are errors that occur during the execution of a Python program. Common exceptions include `TypeError`, `ZeroDivisionError`, `ValueError`, `NameError`, and `FileNotFoundError`, among others.

```python
# ValueError: int() argument must be a string or a number, not a list
num_list = [1, 2, 3]
num = int(num_list)
```

#### Handling Exceptions with try-except Blocks
You can handle exceptions using `try-except` blocks, allowing you to gracefully manage errors and prevent program termination.
```python
try:
    num = int(input("Enter a number: "))
    result = 10 / num
    print("Result:", result)
except ValueError:
    print("Please enter a valid number.")
except ZeroDivisionError:
    print("Cannot divide by zero.")
```

#### Handling Multiple Exceptions
You can handle multiple exceptions in a single `except` block or use separate `except` blocks for each exception type.

```python
try:
    # Code that may raise exceptions
except (ValueError, ZeroDivisionError) as e:
    # Handle multiple exceptions
    print("An error occurred:", e)
```

```python
try:
    # Code that may raise exceptions
except ValueError as ve:
    print("ValueError occurred:", ve)
except ZeroDivisionError as ze:
    print("ZeroDivisionError occurred:", ze)
```

#### Handling All Exceptions
You can also use a generic `except` block to catch all exceptions. However, this approach is not recommended as it may catch unexpected errors and hide bugs.

```python
try:
	# Code that may raise exceptions
except Exception as e:
	# Handle all exceptions
	print("An unexpected error occurred:", e)
```

#### Finally Block
The `finally` block is used to execute cleanup code, such as closing files or releasing resources, regardless of whether an exception occurred or not.

```python
try:
	# Code that may raise exceptions
except SomeException:
	# Handle exception
finally:
	# Cleanup code
```

#### Raising Exceptions
You can raise exceptions manually using the `raise` statement to indicate that an error has occurred under certain conditions.

```python
x = -1
if x < 0:
	raise ValueError("x must be a non-negative number")
```

### Classes
In Python, a class is a blueprint for creating objects. Classes provide a way to organize and structure code by grouping related data and functionality together. Objects created from classes are instances of those classes and can have their own attributes and methods.

#### Defining a Class
To define a class in Python, use the `class` keyword followed by the class name and a colon (`:`). Inside the class definition, you can include attributes and methods.

```python
class MyClass:
	"""A simple example class"""
	
	# Class attribute
	class_variable = 10

	# Constructor method (initializer)
	def __init__(self, name):
		self.name = name  # Instance attribute
	
	# Instance method
	def greet(self):
		return f"Hello, {self.name}!"
```

#### Creating Objects (Instances)
To create an object (instance) of a class, use the class name followed by parentheses (`()`). This calls the class's constructor method (`__init__`) to initialize the object.

```python
# Creating objects of MyClass
obj1 = MyClass("Alice")
obj2 = MyClass("Bob")
```

#### Accessing Attributes and Methods
You can access attributes and methods of an object using dot notation (`.`).

```python
# Accessing attributes
print(obj1.name)  # Output: Alice

# Accessing methods
print(obj2.greet())  # Output: Hello, Bob!
```

#### Class and Instance Attributes
Class attributes are shared among all instances of a class and are defined outside any method within the class. Instance attributes are unique to each instance and are typically initialized within the constructor method.

```python
class Dog:
	species = "Canis familiaris"  # Class attribute
	
	def __init__(self, name, age):
		self.name = name  # Instance attribute
		self.age = age    # Instance attribute
```

#### Inheritance
Inheritance allows a class (subclass) to inherit attributes and methods from another class (superclass). This promotes code reuse and supports hierarchical relationships between classes.

```python
class Animal:
	def speak(self):
		return "Animal speaks"

class Dog(Animal):
	def speak(self):
		return "Woof!"
		
class Cat(Animal):
	def speak(self):
		return "Meow!"
```

#### Encapsulation
Encapsulation is the bundling of data and methods that operate on the data within a class. It helps in hiding the internal implementation details of a class and protecting the data from external interference.

```python
class BankAccount:
	def __init__(self, balance):
		self._balance = balance  # Encapsulated attribute
	
	def deposit(self, amount):
		self._balance += amount

	def withdraw(self, amount):
		if amount <= self._balance:
			self._balance -= amount
		else:
			print("Insufficient funds")
```

#### Polymorphism
Polymorphism allows objects of different classes to be treated as objects of a common superclass. This enables code to be written in a more generic way, promoting flexibility and extensibility.

```python
class Shape:
	def area(self):
		pass

class Rectangle(Shape):
	def __init__(self, length, width):
		self.length = length
		self.width = width
	
	def area(self):
		return self.length * self.width

class Circle(Shape):
	def __init__(self, radius):
		self.radius = radius

	def area(self):
		import math
		return math.pi * self.radius ** 2
```

#### Dataclasses
Python 3.7 introduced the `dataclasses` module, which provides a decorator and functions for automatically adding special methods to classes. Dataclasses are a convenient way to create classes primarily meant to store data, with less boilerplate code.

```python
from dataclasses import dataclass

@dataclass
class Point:
	x: int
	y: int
	
# Usage
p = Point(1, 2)
print(p)  # Output: Point(x=1, y=2)
```

### Decorators
Decorators are a powerful feature in Python that allow you to modify or extend the behavior of functions or methods without changing their implementation. Decorators are implemented using functions themselves and are denoted by the `@` symbol followed by the decorator function name.

#### Function Decorators
Function decorators are the most common type of decorators in Python. They wrap a function, allowing you to execute code before and/or after the wrapped function is called, or modify its behavior.

```python
def my_decorator(func):
	def wrapper():
		print("Something is happening before the function is called.")
		func()  # Call the original function
		print("Something is happening after the function is called.")
	return wrapper

@my_decorator
def say_hello():
	print("Hello!")

# Calling the decorated function	
say_hello()
```

#### Decorator Syntax
The `@decorator_function` syntax is a shorthand for `function = decorator_function(function)`. It applies the decorator function to the function immediately below it.

```python
# Equivalent to: say_hello = my_decorator(say_hello) @my_decorator
def say_hello():
	print("Hello!")
```

#### Decorators with Arguments
Decorators can accept arguments by wrapping them in an additional function. This allows you to customize the behavior of decorators based on parameters.

```python
def repeat(num_times):
	def decorator_repeat(func):
		def wrapper(*args, **kwargs):
			for _ in range(num_times):
				result = func(*args, **kwargs)
			return result
		return wrapper
	return decorator_repeat
	
@repeat(num_times=3)
def greet(name):
	print(f"Hello, {name}!")

# Calling the decorated function
greet("Alice")
```

#### Class Decorators
In addition to function decorators, Python also supports class decorators. Class decorators wrap entire classes instead of individual functions.

```python
def add_methods(cls):
	cls.method1 = lambda self: print("Method 1 added dynamically.")
	cls.method2 = lambda self: print("Method 2 added dynamically.")
	return cls
	
@add_methods
class MyClass:
	pass
	
# Creating an instance of the decorated class
obj = MyClass()
obj.method1()  # Output: Method 1 added dynamically.
```

#### Built-in Decorators
Python provides several built-in decorators, such as `@staticmethod`, `@classmethod`, and `@property`, which are commonly used in object-oriented programming.

```python
class MyClass:
	def __init__(self, value):
		self._value = value
		
	@staticmethod
	def static_method():
		print("This is a static method.")
		
	@classmethod
	def class_method(cls):
		print("This is a class method.")

	@property
	def value(self):
		return self._value
		
# Using the built-in decorators
MyClass.static_method()
MyClass.class_method()
obj = MyClass(10)
print(obj.value)
```

### Standard Library
The Python Standard Library is a collection of modules and packages that provides a wide range of functionality to Python developers. These modules cover various domains such as file I/O, networking, data manipulation, web development, and more. Leveraging the Python Standard Library can save you time and effort by providing pre-built solutions for common tasks. Some of the most commonly used built-in modules include:
- `os`: Operating system interfaces for file and directory manipulation.
- `sys`: System-specific parameters and functions.
- `datetime`: Date and time manipulation.
- `random`: Random number generation.
- `math`: Mathematical functions.
- `json`: [JSON](../../../files/JSON.md) encoding and decoding.
- `io`: Core tools for working with streams.
- `os.path`: Functions for manipulating file paths.
- `shutil`: High-level file operations such as copying and archiving.
- `glob`: Unix-style pathname pattern expansion.
- `tempfile`: Temporary file and directory creation.
- `socket`: Low-level networking interface.
- `http.client`: [HTTP](../../../internet/HTTP.md) client library.
- `urllib`: [URL](../../../internet/URL.md) handling modules.
- `ftplib`: [FTP](../../../internet/FTP.md) client library.
- `smtplib`: [SMTP](../../../internet/SMTP.md) client library for sending [email](../../../internet/eMail.md).
- `csv`: [CSV](../../../files/CSV.md) file reading and writing.
- `pickle`: Object serialization.
- `re`: [Regular expression](../../../tools/Regex.md) matching
- `logging`: Flexible [logging](../../Log.md) system for Python.
- `argparse`: Command-line argument parsing.
- `collections`: Additional data structures beyond the built-in ones.
- `concurrent`: Utilities for concurrent programming.
- `multiprocessing`: Process-based parallelism

### Third Party Modules
- **NumPy**: Fundamental for numerical computing. Provides high-performance multidimensional arrays.
- **Pandas**: Offers data structures and tools for data manipulation and analysis, particularly with labeled data.
- **Matplotlib**: Comprehensive library for creating static, animated, and interactive visualizations.
- **Requests**: Simplifies making [HTTP](../../../internet/HTTP.md) requests, facilitating interaction with web services and APIs.
