Skip to main content

Python Basics

Variables and Data Types

Variables: Variables in Python are used to store data and do not require explicit declaration. They are created when a value is assigned.

age = 25  # Integer
name = "Alice" # String
is_student = True # Boolean

Data Types:

  • int: Integer, e.g., 5
  • float: Floating-point number, e.g., 5.0
  • str: String, e.g., "Hello"
  • bool: Boolean, e.g., True or False
  • NoneType: Represents the absence of value, None

Basic Operators

Arithmetic Operators: +, -, *, /, // (floor division), % (modulus), ** (exponent)

Comparison Operators: ==, !=, <, >, <=, >=

Logical Operators: and, or, not

Precedence and Associativity

In Python, precedence determines the order in which operators are evaluated in an expression, while associativity defines the direction in which operators of the same precedence level are evaluated.

Operator Precedence

Operators with higher precedence are evaluated before operators with lower precedence. For example:

result = 10 + 5 * 2  # Multiplication (*) has higher precedence than addition (+)
print(result) # Output: 20

Here, 5 * 2 is evaluated first, and then 10 + 10.

Operator Associativity

When operators of the same precedence appear together, associativity determines their evaluation order:

  • Left-to-right associativity: Most operators (e.g., +, -, *, /, etc.) are evaluated from left to right.
    result = 10 - 5 + 2  # Evaluated as (10 - 5) + 2
    print(result) # Output: 7
  • Right-to-left associativity: Some operators (e.g., ** for exponentiation and assignment operators like =) are evaluated from right to left.
    result = 2 ** 3 ** 2  # Evaluated as 2 ** (3 ** 2)
    print(result) # Output: 512

Parentheses

To explicitly define the evaluation order, you can use parentheses:

result = (10 + 5) * 2  # Parentheses override default precedence
print(result) # Output: 30

Operator Precedence and Associativity Table

OperatorDescriptionAssociativity
()ParenthesesN/A (Highest precedence)
**ExponentiationRight-to-left
+x, -x, ~xUnary plus, minus, bitwise NOTRight-to-left
*, /, //, %Multiplication, division, floor division, moduloLeft-to-right
+, -Addition, subtractionLeft-to-right
<<, >>Bitwise shift operatorsLeft-to-right
&Bitwise ANDLeft-to-right
^Bitwise XORLeft-to-right
``Bitwise OR
==, !=, >, >=, <, <=, is, is not, in, not inComparison and membership operatorsLeft-to-right
notLogical NOTRight-to-left
andLogical ANDLeft-to-right
orLogical ORLeft-to-right
=, +=, -=, *=, /=, %=, **=, //=Assignment operatorsRight-to-left
lambdaLambda expressionsN/A (Lowest precedence)

List Comprehension

A concise way to create lists based on existing iterables.

squares = [x**2 for x in range(10)]

Basic I/O

Input: input() function to take user input.

name = input("Enter Our name: ")

Output: print() function to display output.

print("Hello, World!")

Mutation

Key Points

  1. Mutable Data Structures:

    • Can be modified after creation.
    • Examples: list, dict, set, bytearray.
  2. Immutable Data Structures:

    • Cannot be modified after creation.
    • Examples: tuple, str, frozenset, bytes, range.

Here is a table summarizing common Python data structures and whether they are mutable or immutable:

Data StructureMutableDescription
List (list)YesCan be modified after creation (e.g., adding, removing, or changing elements).
Tuple (tuple)NoImmutable sequence; cannot be changed after creation.
Dictionary (dict)YesKeys and values can be added, removed, or updated.
Set (set)YesCan add or remove elements; unordered collection of unique elements.
String (str)NoImmutable sequence of characters; cannot be modified after creation.
Frozen Set (frozenset)NoImmutable version of set; cannot add or remove elements.
Bytes (bytes)NoImmutable sequence of bytes (binary data).
Bytearray (bytearray)YesMutable version of bytes; can modify individual bytes.
Range (range)NoImmutable sequence representing a range of numbers.

Unpacking Symbol in Python

In Python, unpacking is a mechanism that allows you to assign values from an iterable (like a list, tuple, or dictionary) to multiple variables in a single step. The unpacking operation is done using the * and ** symbols. Below is a detailed explanation of their usage:

Unpacking with * (Single Asterisk)

The * symbol is used for unpacking elements from iterables (like lists, tuples, or sets).

Unpacking Elements into Variables

The * symbol can capture multiple elements from an iterable into a list.

Example
# Unpacking a list
a, *b, c = [1, 2, 3, 4, 5]
print(a) # 1
print(b) # [2, 3, 4]
print(c) # 5
Explanation
  • a gets the first element.
  • c gets the last element.
  • *b captures all the elements in the middle.

Function Arguments Unpacking

The * symbol can unpack an iterable (like a list or tuple) and pass its elements as arguments to a function.

Example
def add(a, b, c):
return a + b + c

args = [1, 2, 3]
result = add(*args) # Unpacks the list [1, 2, 3] into a, b, c
print(result) # 6

Unpacking in List or Set Literals

You can use * to unpack elements into a new list or set.

Example
# List Unpacking
a = [1, 2, 3]
b = [*a, 4, 5]
print(b) # [1, 2, 3, 4, 5]

# Set Unpacking
s1 = {1, 2, 3}
s2 = {*s1, 4, 5}
print(s2) # {1, 2, 3, 4, 5}

Unpacking for zip() in Matrix Transposition

The * operator can unpack rows of a matrix to pass them as arguments to the zip() function.

Example
matrix = [[1, 2], [3, 4], [5, 6]]
transposed = list(zip(*matrix))
print(transposed) # [(1, 3, 5), (2, 4, 6)]

Collecting Excess Positional Arguments

In function definitions, the * symbol allows you to collect extra positional arguments into a tuple.

Example
def func(a, *args):
print(a) # First argument
print(args) # Remaining arguments as a tuple

func(1, 2, 3, 4) # Output: 1 and (2, 3, 4)

Unpacking with ** (Double Asterisk)

The ** symbol is used for unpacking dictionaries into key-value pairs.

Function Keyword Argument Unpacking

You can use ** to unpack a dictionary and pass its key-value pairs as keyword arguments to a function.

Example
def greet(name, age):
print(f"Hello {name}, you are {age} years old.")

data = {"name": "Alice", "age": 25}
greet(**data) # Equivalent to: greet(name="Alice", age=25)

Merging Dictionaries

You can use ** to unpack multiple dictionaries into a new dictionary.

Example
d1 = {"a": 1, "b": 2}
d2 = {"c": 3, "d": 4}
merged = {**d1, **d2}
print(merged) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

Collecting Keyword Arguments

In function definitions, ** allows you to collect excess keyword arguments into a dictionary.

Example
def func(a, **kwargs):
print(a) # First argument
print(kwargs) # Remaining keyword arguments as a dictionary

func(1, b=2, c=3) # Output: 1 and {'b': 2, 'c': 3}

Combining * and ** in Functions

You can use both * and ** together in function definitions to handle both extra positional and keyword arguments.

Example
def func(a, *args, **kwargs):
print(a) # First argument
print(args) # Extra positional arguments
print(kwargs) # Extra keyword arguments

func(1, 2, 3, b=4, c=5)
# Output:
# 1
# (2, 3)
# {'b': 4, 'c': 5}

Unpacking in For Loops

You can unpack iterables while iterating through them in a loop.

Example

pairs = [(1, 2), (3, 4), (5, 6)]
for a, b in pairs:
print(a, b)
# Output:
# 1 2
# 3 4
# 5 6

Nested Unpacking

Python allows unpacking within nested structures.

Example

nested = [1, (2, 3), 4]
a, (b, c), d = nested
print(a, b, c, d) # 1 2 3 4

Summary of * and ** Usage

SymbolUse CaseDescription
*Unpacking IterablesUsed to unpack lists, tuples, sets, or other iterables.
*Collect Positional ArgumentsCollects extra positional arguments into a tuple.
*List/Set UnpackingUnpacks iterables into new lists or sets.
*For zip() Matrix TranspositionUnpacks rows for transposition.
**Unpacking DictionariesUsed to unpack key-value pairs into function calls or new dictionaries.
**Collect Keyword ArgumentsCollects extra keyword arguments into a dictionary.