Variables in Python
In Python, variables are names that refer to objects in memory. Unlike statically typed languages, you do not declare a variable's type — Python infers it at runtime. A variable is created the moment you assign a value to it. Variables in Python are essentially labels or pointers to objects, not containers that hold values directly.
# Variable assignment - no type declaration needed
name = "Alice"
age = 30
pi = 3.14159
is_active = True
# Multiple assignment
x, y, z = 1, 2, 3
# Same value to multiple variables
a = b = c = 0
# Swap variables (Pythonic way)
x, y = y, x
print(x, y) # 2, 1
# Variable naming conventions (PEP 8)
user_name = "bob" # snake_case for variables and functions
MAX_RETRIES = 3 # UPPER_CASE for constants
_private_var = "hidden" # leading underscore for private
Numeric Types
Python has three built-in numeric types: int (integers with arbitrary precision), float (64-bit double-precision floating point), and complex (complex numbers with real and imaginary parts). Python integers have no size limit — they can be as large as your memory allows.
# Integers - arbitrary precision
small = 42
big = 10 ** 100 # A googol - no overflow!
binary = 0b1010 # 10 in binary
octal = 0o17 # 15 in octal
hexadecimal = 0xFF # 255 in hex
readable = 1_000_000 # Underscores for readability
# Floats - double precision
pi = 3.14159
scientific = 2.5e-3 # 0.0025
infinity = float('inf')
not_a_number = float('nan')
# Integer division vs float division
print(7 / 2) # 3.5 (true division)
print(7 // 2) # 3 (floor division)
print(7 % 2) # 1 (modulo)
print(2 ** 10) # 1024 (exponentiation)
# Complex numbers
z = 3 + 4j
print(z.real) # 3.0
print(z.imag) # 4.0
print(abs(z)) # 5.0 (magnitude)
Strings
Strings in Python are immutable sequences of Unicode characters. You can create them with single quotes, double quotes, or triple quotes for multi-line strings. Python 3 strings are Unicode by default, supporting characters from virtually every language and symbol set.
# String creation
single = 'Hello'
double = "World"
triple = """This is a
multi-line string"""
# f-strings (formatted string literals) - Python 3.6+
name = "Alice"
age = 30
greeting = f"Hello, {name}! You are {age} years old."
calc = f"2 + 2 = {2 + 2}"
formatted = f"Pi is approximately {3.14159:.2f}"
# String methods (strings are immutable - methods return new strings)
text = "Hello, World!"
print(text.upper()) # "HELLO, WORLD!"
print(text.lower()) # "hello, world!"
print(text.replace("World", "Python")) # "Hello, Python!"
print(text.split(", ")) # ["Hello", "World!"]
print(" spaces ".strip()) # "spaces"
print(text.startswith("Hello")) # True
print(text.find("World")) # 7
print(text.count("l")) # 3
# String slicing
s = "Python"
print(s[0]) # 'P'
print(s[-1]) # 'n'
print(s[0:3]) # 'Pyt'
print(s[::-1]) # 'nohtyP' (reverse)
# Raw strings (no escape processing)
path = r"C:Users
ew_folder est"
Booleans and None
bool is a subclass of int in Python. True equals 1 and False equals 0. None is Python's null value, representing the absence of a value. It is a singleton — there is only one None object in memory.
# Booleans
is_valid = True
is_empty = False
# Truthy and falsy values
# Falsy: False, 0, 0.0, "", [], {}, set(), None, 0j
# Everything else is truthy
print(bool(0)) # False
print(bool(42)) # True
print(bool("")) # False
print(bool("hello")) # True
print(bool([])) # False
print(bool([1, 2])) # True
# None
result = None
if result is None:
print("No result yet")
# Always use 'is' for None comparison, not '=='
# This is because 'is' checks identity, '==' checks equality
x = None
print(x is None) # True (correct)
print(x == None) # True (works but not Pythonic)
Type Conversion
Python provides built-in functions for converting between types. These are called type constructors and include int(), float(), str(), bool(), list(), tuple(), set(), and dict().
# Explicit type conversion
num_str = "42"
num_int = int(num_str) # 42
num_float = float(num_str) # 42.0
pi = 3.14159
pi_int = int(pi) # 3 (truncates, does not round)
pi_str = str(pi) # "3.14159"
# Converting between collections
my_list = [1, 2, 3, 2, 1]
my_set = set(my_list) # {1, 2, 3}
my_tuple = tuple(my_list) # (1, 2, 3, 2, 1)
back_to_list = list(my_set) # [1, 2, 3]
# Be careful with conversions
int("hello") # ValueError!
int("3.14") # ValueError! (use float() first)
int(float("3.14")) # 3 (this works)
The id() Function and Memory Model
Every object in Python has a unique identity (memory address), a type, and a value. The id() function returns the identity, type() returns the type, and the variable gives you the value. Python caches small integers (-5 to 256) and short strings for performance.
# Identity vs equality
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True (same value)
print(a is b) # False (different objects)
print(a is c) # True (same object)
print(id(a) == id(c)) # True
# Integer caching
x = 256
y = 256
print(x is y) # True (cached)
x = 257
y = 257
print(x is y) # May be False (not cached)
# type() and isinstance()
print(type(42)) #
print(type("hello")) #
print(isinstance(42, int)) # True
print(isinstance(42, (int, float))) # True (check multiple types)
Key Takeaways
- Dynamic typing: Variables are labels pointing to objects, not typed containers
- Integers have no limit: Python ints have arbitrary precision
- Strings are immutable: Methods return new strings, they do not modify in place
- Use f-strings: They are the most readable way to format strings
- Use 'is' for None: Always compare to None with 'is', not '=='