Unit 3: Data Structures, Classes, and Inheritance
I. Orientation
Python programming combines built-in collection types with object-oriented mechanisms for organizing data and behavior. Data structures store values, while classes define reusable models whose instances possess attributes and methods. Python’s dynamic typing, object references, and emphasis on iteration connect these topics closely.
- Objects and references: Every value is an object; a variable such as
x = [1, 2]refers to a list object rather than containing an independent copy. - Mutability: Mutable objects can change in place; immutable objects require creation of a new object for a changed value.
- Iteration:
forloops and tools such asenumerate(),zip(), anditertoolsprocess iterable objects systematically. - Abstraction: Classes package data and operations, while inheritance reuses or specializes existing class definitions.
- Python conventions: Indentation defines blocks,
selfrefers to the current instance, and names beginning with_conventionally indicate internal use.
II. Lists — Ordered, mutable collections
A list is an ordered, zero-indexed collection that can contain duplicate and mixed-type values.
A. Lists
Lists support creation, indexing, slicing, insertion, deletion, and in-place updates.
- Creation:
numbers = [10, 20, 30];list("cat")creates['c', 'a', 't']. - Access:
numbers[0]is10;numbers[-1]is30;numbers[1:]produces[20, 30]. - Manipulation:
append(40)adds one item,extend([50, 60])adds several, andinsert(1, 15)inserts at index1. - Removal:
remove(20)deletes the first matching value, whilepop()removes and returns the last item. - Mutability:
numbers[0] = 5changes the existing list object; list methods such assort()andreverse()usually returnNone.
B. List comprehension
A list comprehension creates a list through a compact expression containing iteration and optional filtering.
- Basic form:
[expression for item in iterable];[x * x for x in range(4)]gives[0, 1, 4, 9]. - Condition:
[x for x in range(10) if x % 2 == 0]retains only even values. - Nested processing:
[a + b for a in [1, 2] for b in [10, 20]]creates four sums. - Readability: Comprehensions are best for simple transformations; several nested conditions may be clearer as ordinary loops.
III. Tuples — Immutable sequences
A tuple is an ordered sequence whose structure cannot be changed after creation.
A. Tuples
Tuples support indexing, slicing, unpacking, and repeated or mixed values, but not item assignment.
- Creation:
point = (3, 4); a one-item tuple requires a comma:single = (7,). - Access:
point[0]returns3, andlen(point)returns2. - Unpacking:
x, y = pointassignsx = 3andy = 4; starred unpacking can collect remaining values. - Immutability:
point[0] = 8raisesTypeError, making tuples suitable for fixed records and dictionary keys when their contents are hashable. - Nested mutability: A tuple may contain a mutable list, such as
t = ([1], 2);t[0].append(3)is allowed because the list changes, not the tuple structure.
IV. Dictionaries — Key–value mappings
A dictionary maps unique, hashable keys to values and preserves insertion order in modern Python.
A. Dictionaries
Dictionaries provide efficient lookup by key and can be created, updated, traversed, and deleted.
- Creation:
student = {"name": "Mira", "mark": 88};dict(city="Pune")creates{"city": "Pune"}. - Access:
student["mark"]returns88;student.get("age", 0)avoids an exception when"age"is absent. - Manipulation:
student["mark"] = 91updates a value;student["passed"] = Trueadds a key. - Traversal:
student.items()yields key–value pairs, whilefor key, value in student.items():processes both. - Mutability: Dictionaries change in place, but keys must be hashable; lists cannot be keys, whereas strings and tuples of immutable values can be.
V. Sets — Unique unordered collections
Sets store unique hashable elements and are useful for membership testing and mathematical operations.
A. Sets: creation, manipulation, and mutability
Sets can be changed in place, while frozenset provides an immutable alternative.
- Creation:
a = {1, 2, 3};set([1, 1, 2])produces{1, 2};{}creates an empty dictionary, so useset()for an empty set. - Manipulation:
add(4)inserts an item,discard(2)removes it without failure if absent, andremove(2)raisesKeyErrorif absent. - Operations: For sets
AandB,A | Bis union,A & Bintersection,A - Bdifference, andA ^ Bsymmetric difference. - Mutability:
A.update(B)changesA;frozenset(A)cannot be modified and may be used as a dictionary key. - Ordering: Set iteration order should not be relied upon; use
sorted(A)when ordered output is required.
VI. Functional and Iteration Tools
Python supplies functions that transform, select, combine, and lazily traverse iterable data.
A. Map
map() applies a function to every item and returns a lazy iterator.
- Form:
map(function, iterable);list(map(str.upper, ["a", "b"]))produces['A', 'B']. - Multiple inputs:
map(pow, [2, 3], [3, 2])computes2**3and3**2; iteration stops at the shortest input. - Efficiency: Results are generated when consumed, avoiding an immediate result list.
B. Filter
filter() retains items for which a function returns a truthy value.
- Form:
filter(predicate, iterable);list(filter(lambda n: n > 5, [3, 6, 8]))gives[6, 8]. - Predicate: A predicate returns
TrueorFalse;filter(None, values)removes false-like values such as0and"". - Comparison: A comprehension such as
[n for n in values if n > 5]is often more readable.
C. Reduce
reduce() repeatedly combines items into one result and is imported from functools.
- Form:
reduce(function, iterable, initializer);reduce(lambda a, b: a + b, [1, 2, 3], 0)returns6. - Process: The function first combines
0with1, then the result with2, and finally with3. - Limitation: Built-ins such as
sum()are clearer for common operations; usereduce()when a genuine cumulative combination is needed.
D. Cartesian product
A Cartesian product contains every ordered combination formed by selecting one item from each input.
- Definition: For
A = [1, 2]andB = ['x', 'y'], the product is(1, 'x),(1, 'y'),(2, 'x'), and(2, 'y'). - Python tool:
itertools.product(A, B)generates these pairs lazily. - Size: If input lengths are
mandn, the result hasm × ncombinations.
E. Itertools
The itertools module provides efficient iterator building blocks.
- Infinite tools:
count(10, 2)generates10, 12, 14, ...; combine it withislice()to impose a limit. - Selection tools:
chain([1, 2], [3])joins iterables, whileislice(range(10), 2, 5)selects indices2through4. - Grouping:
groupby()groups consecutive equal-key items, so data generally must be sorted by the same key first. - Laziness: Most tools produce values only when requested, reducing memory use for large streams.
VII. Built-in Evaluation and Pairing Tools
These functions interpret expressions or organize iterable positions and relationships.
A. eval
eval() evaluates a string containing a Python expression and returns its value.
- Example:
eval("2 + 3 * 4")returns14; expressions may include literals, operators, and function calls. - Scope: Optional
globalsandlocalsdictionaries control available names. - Safety: Never evaluate untrusted input because
eval()can access dangerous operations through Python expressions.
B. exec
exec() executes Python statements from a string and normally returns None.
- Example:
exec("x = 5\nprint(x)")assigns and prints5. - Capability: Unlike
eval(), it can execute assignments, loops, imports, and function definitions. - Safety: Untrusted strings must never be passed to
exec(); prefer explicit parsing or predefined operations.
C. enumerate
enumerate() produces index–value pairs while iterating.
- Example:
for i, item in enumerate(["a", "b"], start=1):produces(1, "a")and(2, "b"). - Advantage: It avoids manually maintaining and incrementing a counter.
D. zip
zip() combines corresponding elements from multiple iterables.
- Example:
dict(zip(["a", "b"], [1, 2]))creates{"a": 1, "b": 2}. - Length rule: Normal
zip()stops at the shortest input;zip(..., strict=True)can report mismatched lengths in supported Python versions.
E. copy
Copying determines whether nested objects remain shared.
- Assignment:
b = acreates another reference to the same object; changingbchangesa. - Shallow copy:
b = a.copy()duplicates the outer list, but nested lists remain shared. - Deep copy:
copy.deepcopy(a)recursively copies nested objects; it is imported fromcopyand may be expensive.
VIII. Classes and Object Construction
Classes define the blueprint and behavior of related objects.
A. Introduction to classes
A class combines state and behavior through attributes and methods.
- Definition:
class Car:begins a class block; an instance is created withCar(). - Purpose: A
Carclass can represent data such ascolorand actions such asstart(). - Encapsulation: Methods provide controlled operations instead of exposing every implementation detail.
B. Constructors
The constructor initializes a newly created instance, conventionally through __init__().
- Example:
def __init__(self, name): self.name = namestores the suppliedname. - Invocation:
p = Person("Asha")automatically callsPerson.__init__(p, "Asha"). - Special method:
__init__()initializes an object; object allocation is handled separately by__new__().
C. Methods
Methods are functions defined inside a class and usually receive the instance as self.
- Instance method:
def area(self): return self.width * self.heightreads instance data. - Class method:
@classmethodreceivesclsand can construct or modify class-level state. - Static method:
@staticmethodreceives neither automaticselfnorclsand is suitable for utility logic related to the class.
D. Attributes
Attributes store object or class state.
- Instance attributes:
self.balance = 100gives each account its own balance. - Class attributes:
species = "Canis familiaris"is shared unless shadowed by an instance attribute. - Access control: Python uses conventions such as
_name;__nametriggers name mangling rather than strict private access.
E. Instances
An instance is a concrete object created from a class.
- Identity:
a = Account(); b = Account()creates two distinct objects, tested witha is not b. - State:
a.balanceandb.balancemay hold different values because each has separate instance attributes. - Behavior:
a.deposit(50)invokes the class method withaautomatically supplied asself.
IX. Inheritance — Reusing and specializing classes
Inheritance creates a derived class from a base class, allowing shared behavior and controlled specialization.
A. Inheritance concepts
Inheritance models an “is-a” relationship and supports reuse, extension, and polymorphism.
- Relationship: If
Doginherits fromAnimal, everyDogis anAnimal, but not everyAnimalis aDog. - Lookup: Python searches the instance’s class and then its method resolution order, or MRO.
- Polymorphism: Code can call
animal.speak()without knowing whether the object is aDogor another subclass.
B. Base and derived classes
A base class supplies common features, while a derived class adds or changes features.
- Syntax:
class Dog(Animal):declaresAnimalas the base andDogas the derived class. - Initialization:
super().__init__(name)invokes the base initializer without naming the base directly. - Reuse: Common validation belongs in
Animal; dog-specific behavior belongs inDog.
C. Method overriding
Overriding occurs when a derived class defines a method with the same name as one in its base class.
- Example:
Dog.speak()may return"Woof"instead of the baseAnimal.speak()result. - Extension: An overriding method can call
super().speak()and then add subclass-specific output. - Polymorphic effect: Calling
obj.speak()selects the implementation appropriate toobj’s actual type.
D. Multiple inheritance
Multiple inheritance allows a class to inherit from more than one base class.
- Syntax:
class SmartPhone(Camera, Phone):combines capabilities from both parents. - MRO: Python’s C3 linearization determines lookup order;
SmartPhone.__mro__displays that sequence. - Cooperative design: Each class should use
super()and compatible signatures to ensure every initializer participates once. - Risk: Conflicting methods and diamond-shaped hierarchies can make behavior difficult to reason about.
E. Practical OOP examples
A practical class should model a coherent entity with validated state and meaningful operations.
- Example: A
BankAccountmay defineowner,_balance,deposit(amount), andwithdraw(amount). - Validation:
withdraw()should reject an amount greater than the balance rather than allowing invalid state. - Design principle: Keep data and operations together; a
LibraryBookcan exposecheckout()andreturn_book()instead of permitting arbitrary status changes.
X. Use of decorators and generators
Decorators modify callable behavior, while generators produce sequences lazily.
A. Use of decorators and generators
These mechanisms support reusable control logic and memory-efficient iteration.
- Decorator: A function receiving another function can wrap it;
@log_callabovefis equivalent tof = log_call(f). - Preservation:
functools.wraps()copies metadata such as the original function’s name and documentation. - Generator: A function containing
yieldreturns an iterator;yield npauses execution and resumes on the nextnext()call. - Memory benefit:
def squares(n): yield i*iproduces values one at a time rather than storing allnresults in a list. - Combination: A decorator can measure a generator function, but it should preserve lazy behavior instead of eagerly converting the generator to a list.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →