What you'll learn
Quick Answer
The essentials are the built-in types and their methods, comprehensions, f-strings, functions with default and keyword arguments, file handling with the with statement, and basic classes. Beyond syntax, a handful of idioms — enumerate, zip, unpacking, and truthiness checks — are what make code read as Python rather than as another language transcribed.
Types, Variables and Strings
# Types
x = 42 # int
y = 3.14 # float
name = "Riya" # str
flag = True # bool
nothing = None # NoneType
type(x) # <class 'int'>
int("42"), float("3.14"), str(42), bool(0)
# f-strings — the modern way to format
f"{name} is {x} years old"
f"{3.14159:.2f}" # '3.14' — 2 decimal places
f"{1234567:,}" # '1,234,567'
f"{x=}" # 'x=42' — handy for debugging
# String methods (all return new strings — str is immutable)
s = " Hello World "
s.strip() # 'Hello World'
s.lower(), s.upper(), s.title()
s.replace("World", "There")
s.split() # ['Hello', 'World']
",".join(['a', 'b', 'c']) # 'a,b,c'
s.startswith(" He"), s.endswith(" ")
"World" in s # True
# Slicing works on any sequence
s[0], s[-1], s[2:5], s[:3], s[3:], s[::-1] # last one reversesRemember strings are immutable. Every method returns a new string, so s.strip() alone does nothing — you must assign the result. Building a string by repeated concatenation in a loop is O(n squared); collect the pieces in a list and join once instead.
Lists, Dicts, Sets and Tuples
# List — ordered, mutable
nums = [3, 1, 4, 1, 5]
nums.append(9); nums.insert(0, 7); nums.extend([2, 6])
nums.remove(1) # removes the FIRST 1
nums.pop(); nums.pop(0) # pop(0) is O(n) — use deque for queues
nums.sort(); nums.sort(reverse=True); nums.sort(key=len)
sorted(nums) # returns a NEW list, does not mutate
nums.reverse(); nums.count(1); nums.index(4)
len(nums), min(nums), max(nums), sum(nums)
# Dict — key-value, insertion ordered since 3.7
user = {'name': 'Riya', 'age': 20}
user['city'] = 'Pune'
user.get('email') # None instead of KeyError
user.get('email', 'not set') # with a default
user.keys(), user.values(), user.items()
user.pop('age'); 'name' in user
{**user, 'age': 21} # merge / override
for key, value in user.items():
print(key, value)
# Set — unique, unordered, O(1) membership
s = {1, 2, 3}
s.add(4); s.discard(9) # discard does not raise if absent
s1 | s2, s1 & s2, s1 - s2 # union, intersection, difference
list(set(nums)) # deduplicate
# Tuple — immutable, hashable, usable as a dict key
point = (3, 4)
x, y = point # unpacking
a, *rest = [1, 2, 3, 4] # a=1, rest=[2,3,4]
Control Flow and Comprehensions
# Conditionals
if x > 10:
...
elif x > 5:
...
else:
...
status = "adult" if age >= 18 else "minor" # ternary
# Truthiness — empty things are falsy
if not items: # preferred over if len(items) == 0
if value is None: # use 'is' for None, never ==
# Loops
for i in range(5): # 0..4
for i in range(2, 10, 2): # 2,4,6,8
for item in items:
for i, item in enumerate(items, start=1):
for a, b in zip(list1, list2):
while condition:
...
break / continue
else:
... # runs only if the loop finished without break
# Comprehensions — the most Pythonic construct
[x * 2 for x in nums]
[x for x in nums if x > 2]
[x if x > 0 else 0 for x in nums] # note: ternary goes BEFORE 'for'
{k: v for k, v in pairs}
{x for x in nums} # set comprehension
(x * 2 for x in nums) # generator — lazy, memory-friendly
[[r[i] for r in matrix] for i in range(len(matrix[0]))] # transposeKeep comprehensions to one condition and one transformation. Once you need nested loops and multiple conditions, a normal loop reads better — clever is not the goal.
Functions, Files and Errors
# Functions
def greet(name, greeting="Hello"): # default argument
return f"{greeting}, {name}"
def total(*args, **kwargs): # variable arguments
return sum(args)
greet(name="Riya", greeting="Hi") # keyword arguments
square = lambda x: x * x # lambda — for short callbacks only
# NEVER use a mutable default — it is created once, at definition time
def bad(item, items=[]): ... # accumulates across calls
def good(item, items=None):
if items is None: items = []
# Files — always use 'with', always specify encoding
with open('data.txt', 'r', encoding='utf-8') as f:
content = f.read()
for line in f: # memory-friendly for large files
process(line.rstrip())
with open('out.txt', 'w', encoding='utf-8') as f: # 'w' TRUNCATES immediately
f.write('text')
# JSON
import json
data = json.load(f) # from a file object
data = json.loads(string) # from a string (the 's' means string)
json.dump(data, f, indent=2)
# Errors
try:
result = 10 / n
except ZeroDivisionError as e:
print(f"error: {e}")
except (TypeError, ValueError):
...
else:
print("no exception occurred")
finally:
print("always runs — cleanup goes here")
raise ValueError("invalid input")
Classes and the Idioms That Matter
class Student:
school = "Priodemy" # class attribute, shared
def __init__(self, name, marks): # constructor
self.name = name # instance attributes
self.marks = marks
def __str__(self): # what print() shows
return f"{self.name}: {self.marks}"
def __repr__(self): # what the debugger shows
return f"Student({self.name!r}, {self.marks})"
def passed(self):
return self.marks >= 40
@staticmethod
def is_valid(marks):
return 0 <= marks <= 100
@classmethod
def from_string(cls, s): # alternative constructor
name, marks = s.split(',')
return cls(name, int(marks))
class Topper(Student): # inheritance
def __init__(self, name, marks, rank):
super().__init__(name, marks)
self.rank = rankThe idioms that make code look like Python:
for i, x in enumerate(items): # not for i in range(len(items))
for a, b in zip(l1, l2): # not indexing both
if not items: # not if len(items) == 0
a, b = b, a # swap without a temp variable
with open(...) as f: # not open / close by hand
value = d.get(k, default) # not if k in d: ... else: ...
text = "".join(parts) # not += in a loop
if x is None: # not if x == NoneUseful standard-library modules to know exist: collections for Counter, defaultdict and deque; itertools for combinations and permutations; datetime; pathlib for filesystem paths; random; and math.
