Python is dynamically typed — you don't declare types, the interpreter infers them at runtime.
# No type declaration needed
x = 42 # Python knows this is int
name = 'Alice' # Python knows this is str
pi = 3.14 # Python knows this is float
# Type can change at runtime (reassignment)
x = 'now a string' # Perfectly valid!
# Check types
print(type(x)) # <class 'str'>
print(type(pi)) # <class 'float'>
print(type(True)) # <class 'bool'>
print(type(None)) # <class 'NoneType'># ✅ Valid names
age = 25
_first_name = 'John'
num2 = 10
privateVar = True
MAX_SIZE = 100
# ❌ INVALID names
# 2nd_place = 5 # Cannot start with number
# my-var = 10 # No hyphens (interpreted as minus)
# class = 'A' # Cannot use keyword
# my name = 'John' # No spacesConventions (PEP 8):
snake_case for variables and functionsUPPER_SNAKE_CASE for constants_leading_underscore for internal/private__dunder__ for magic methodsx = 42
big = 999999999999999999999999999999999999999999999
print(type(big)) # <class 'int'> — NO overflow!
# Different number bases
binary = 0b1010 # 10 in decimal
octal = 0o17 # 15 in decimal
hex_val = 0xFF # 255 in decimal
# Underscore separators for readability (Python 3.6+)
million = 1_000_000
credit_card = 4000_1234_5678_9010pi = 3.14159
scientific = 2.5e4 # 25000.0
negative = -0.001
# ⚠️ Floating point precision issue
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False!
# Solution: use round() or decimal module
print(round(0.1 + 0.2, 1)) # 0.3
# Special values
print(float('inf')) # infinity
print(float('-inf')) # -infinity
print(float('nan')) # Not a Number# Different quote styles
single = 'hello'
double = "world"
multi = '''line1
line2'''
# Escape sequences
print('Hello\nWorld') # Newline
print('Tab\there') # Tab
print('Quote: \'hi\'') # Escaped quote
print(r'Raw\nString') # Raw string — no escape processing
# str is IMMUTABLE
s = 'hello'
# s[0] = 'H' # TypeError! Cannot change individual characters
s = 'Hello' # This creates a NEW string objecta = True
b = False
# bool is a subclass of int!
print(True + True) # 2
print(isinstance(True, int)) # True
print(False == 0) # True
print(True == 1) # True
# But they are DIFFERENT objects
print(True is 1) # False
print(type(True)) # <class 'bool'>x = None
print(type(x)) # <class 'NoneType'>
# None is a SINGLETON — only one None object exists
a = None
b = None
print(a is b) # True (same object in memory)
# Common use: default/unset state
def find_user(id):
if id not in database:
return None
return database[id]
# Check for None
if result is None: # ✅ Preferred
print('Not found')
if result == None: # ⚠️ Works but not recommended
print('Not found')
if not result: # ⚠️ Dangerous! Also catches 0, '', [], False
print('Not found')Create variables of each type: int (a 10-digit number with underscores), float (a scientific notation number), str (using both quote styles), bool, and None. Print each variable with its type using f-strings. Then demonstrate the 0.1 + 0.2 precision issue and fix it with round(). Finally, prove that None is a singleton using 'is'.