Day 14 – Basic Classes and Objects
🏗️ Day 14 – Basic Classes and Objects
1. Learning Objectives
By the end of Day 14, you will be able to:
- Understand the difference between a class (blueprint) and an object (instance).
- Define your own classes with attributes (data) and methods (functions).
- Use the special
__init__method to initialise objects with custom data. - Create multiple instances representing real AEC elements (beams, rooms, columns).
- Write a
__str__method to control how objects are printed. - Organise related data and behaviour together – the foundation of Object‑Oriented Programming.
2. Concept Explanation
2.1 Why OOP in AEC?
In the built environment, we naturally think in terms of objects:
- A beam has a span, load, depth, and can compute its moment and deflection.
- A room has length, width, height, and can compute its area and volume.
- A building contains a list of floors, each with its own properties.
OOP lets you model these real‑world entities directly in code. Instead of scattering data across lists and dictionaries, you bundle data and the functions that operate on it into a single unit – a class.
2.2 Defining a Class
A class is defined with the class keyword. The __init__ method (constructor) runs when you create a new instance.
class Beam:
"""A class representing a simply supported steel beam."""
def __init__(self, mark, span, load):
"""Initialise a Beam with mark, span (m), and UDL (kN/m)."""
self.mark = mark
self.span = span
self.load = load
def moment(self):
"""Calculate maximum bending moment (kNm)."""
return self.load * self.span**2 / 8
def shear(self):
"""Calculate maximum shear force (kN)."""
return self.load * self.span / 2
def __str__(self):
"""Return a readable string representation."""
return f"Beam {self.mark}: span={self.span}m, load={self.load}kN/m"
2.3 Creating Objects (Instances)
# Create two beam objects
b1 = Beam("B1", 6.0, 25)
b2 = Beam("B2", 4.5, 18)
# Access attributes and call methods
print(b1) # Calls __str__: "Beam B1: span=6.0m, load=25.0kN/m"
print(f"Moment: {b1.moment():.1f} kNm")
print(f"Shear: {b1.shear():.1f} kN")
# Store objects in a list
beams = [b1, b2]
for b in beams:
print(f"{b.mark}: M={b.moment():.1f} kNm")
2.4 Key OOP Concepts for Today
| Concept | Meaning | AEC Example |
|---|---|---|
| Class | Blueprint or template | class Column: |
| Object | An instance of a class | col1 = Column("C1", 3.5, 1200) |
| Attribute | Data stored on the object (self.xxx) | self.height, self.load |
| Method | A function that belongs to the object | col1.capacity() |
__init__ | Constructor – runs when object created | Sets initial attribute values |
__str__ | String representation for print() | Human‑readable description |
3. Code Examples
Example 1: Room class with area and volume
class Room:
"""A rectangular room with length, width, and height."""
def __init__(self, name, length, width, height):
self.name = name
self.length = length
self.width = width
self.height = height
def area(self):
"""Floor area in m²."""
return self.length * self.width
def volume(self):
"""Volume in m³."""
return self.length * self.width * self.height
def __str__(self):
return f"{self.name}: {self.length}x{self.width}x{self.height}m"
# Create rooms
lobby = Room("Lobby", 10.0, 8.0, 4.0)
office = Room("Open Office", 15.0, 10.0, 3.5)
print(lobby)
print(f" Area: {lobby.area():.1f} m², Volume: {lobby.volume():.1f} m³")
print(office)
print(f" Area: {office.area():.1f} m², Volume: {office.volume():.1f} m³")
Example 2: Column class with capacity check
class Column:
"""A steel column with a design capacity check."""
def __init__(self, mark, height, axial_load, steel_grade="S275"):
self.mark = mark
self.height = height # m
self.axial_load = axial_load # kN
self.steel_grade = steel_grade
# Capacity lookup based on steel grade (simplified)
self.capacity = {
"S235": 1000,
"S275": 1200,
"S355": 1500
}.get(steel_grade, 1000) # kN
def utilization(self):
"""Return load / capacity ratio."""
return self.axial_load / self.capacity
def is_safe(self):
"""Return True if utilization ≤ 1.0."""
return self.utilization() <= 1.0
def __str__(self):
status = "SAFE" if self.is_safe() else "OVERSTRESSED"
return f"Column {self.mark} ({self.steel_grade}): {self.utilization():.0%} utilised – {status}"
# Test columns
columns = [
Column("C1", 3.5, 850, "S275"),
Column("C2", 4.0, 1100, "S275"),
Column("C3", 3.0, 600, "S355"),
]
for col in columns:
print(col)
Example 3: Floor class – a building storey
class Floor:
"""A single floor in a building."""
def __init__(self, name, level, height, usage):
self.name = name
self.level = level # e.g., 1, 2, 3
self.height = height # floor-to-floor height (m)
self.usage = usage # e.g., "Office", "Retail"
self.rooms = [] # list of Room objects
def add_room(self, room):
"""Add a Room object to this floor."""
self.rooms.append(room)
def total_area(self):
"""Sum of all room areas on this floor."""
return sum(room.area() for room in self.rooms)
def __str__(self):
return f"Level {self.level}: {self.name} ({self.usage}) – {len(self.rooms)} rooms"
# Create a floor and add rooms
ground = Floor("Ground Floor", 0, 4.5, "Retail")
ground.add_room(Room("Shop A", 8.0, 6.0, 4.5))
ground.add_room(Room("Shop B", 10.0, 5.0, 4.5))
ground.add_room(Room("Lobby", 6.0, 4.0, 4.5))
print(ground)
print(f" Total retail area: {ground.total_area():.1f} m²")
Example 4: Building class – managing multiple floors
class Building:
"""A multi‑storey building composed of Floor objects."""
def __init__(self, name, address):
self.name = name
self.address = address
self.floors = []
def add_floor(self, floor):
self.floors.append(floor)
def total_height(self):
return sum(f.height for f in self.floors)
def total_area(self):
return sum(f.total_area() for f in self.floors)
def floor_count(self):
return len(self.floors)
def summary(self):
"""Print a formatted summary of the building."""
print(f"\n{'='*50}")
print(f"BUILDING: {self.name}")
print(f"Address: {self.address}")
print(f"{'='*50}")
print(f"{'Floor':<20} {'Height':<10} {'Usage':<15} {'Area (m²)':<10}")
print("-" * 55)
for f in self.floors:
print(f"{f.name:<20} {f.height:<10.1f} {f.usage:<15} {f.total_area():<10.1f}")
print("-" * 55)
print(f"{'TOTAL':<20} {self.total_height():<10.1f} {'':<15} {self.total_area():<10.1f}")
print(f"\nFloors: {self.floor_count()}, Total height: {self.total_height():.1f}m")
print(f"Total floor area: {self.total_area():.1f} m²")
# Build a simple building
building = Building("Riverside Tower", "100 River Rd, Manila")
level1 = Floor("Ground Floor", 0, 4.5, "Retail")
level1.add_room(Room("Shop A", 8, 6, 4.5))
level1.add_room(Room("Shop B", 10, 5, 4.5))
level2 = Floor("Level 2", 1, 3.5, "Office")
level2.add_room(Room("Office 201", 12, 8, 3.5))
level2.add_room(Room("Office 202", 10, 8, 3.5))
level3 = Floor("Level 3", 2, 3.5, "Office")
level3.add_room(Room("Office 301", 12, 8, 3.5))
building.add_floor(level1)
building.add_floor(level2)
building.add_floor(level3)
building.summary()
Example 5: Adding a property decorator (optional preview)
class Material:
"""Material with density and cost per unit volume."""
def __init__(self, name, density, unit_cost):
self.name = name
self.density = density # kg/m³
self.unit_cost = unit_cost # $/m³
@property
def weight_per_m3(self):
"""Weight in kN/m³ (using g ≈ 9.81 m/s²)."""
return self.density * 9.81 / 1000
concrete = Material("Concrete C30", 2400, 95)
print(f"{concrete.name}: {concrete.weight_per_m3:.2f} kN/m³")
4. Hands‑on Exercises (3–5 Problems)
Problem 1 – Simple Wall class
Define a Wall class with attributes: length, height, thickness (all in metres).
Add a method volume() that returns length * height * thickness.
Create two wall instances and print their volumes.
Problem 2 – Slab class with cost estimate
Define a Slab class with attributes: length, width, thickness, unit_cost (cost per m³).
Add methods: volume() and cost().
Create a slab 12m x 8m x 0.2m with unit cost $95/m³. Print volume and cost.
Problem 3 – StructuralElement base class
Create a base class StructuralElement with attributes: mark, material, weight_per_m.
Add a method total_weight(span) that returns weight_per_m * span.
Then create a subclass Beam that inherits from StructuralElement and adds span, load attributes, and a moment() method.
Test by creating a beam instance.
Problem 4 – Project class managing multiple beams
Define a Project class that holds a list of Beam objects (use the Beam class from Example 1).
Add methods: add_beam(beam), total_steel_weight(kg_per_m), average_span().
Create a project with at least 3 beams and print the average span.
Solutions (attempt first):
# P1
class Wall:
def __init__(self, length, height, thickness):
self.length = length
self.height = height
self.thickness = thickness
def volume(self):
return self.length * self.height * self.thickness
w1 = Wall(5.0, 3.0, 0.2)
w2 = Wall(4.0, 3.0, 0.15)
print(f"Wall 1 volume: {w1.volume():.2f} m³")
print(f"Wall 2 volume: {w2.volume():.2f} m³")
# P2
class Slab:
def __init__(self, length, width, thickness, unit_cost):
self.length = length; self.width = width
self.thickness = thickness; self.unit_cost = unit_cost
def volume(self):
return self.length * self.width * self.thickness
def cost(self):
return self.volume() * self.unit_cost
slab = Slab(12, 8, 0.2, 95)
print(f"Volume: {slab.volume():.2f} m³, Cost: ${slab.cost():.2f}")
# P3
class StructuralElement:
def __init__(self, mark, material, weight_per_m):
self.mark = mark; self.material = material; self.weight_per_m = weight_per_m
def total_weight(self, span):
return self.weight_per_m * span
class Beam(StructuralElement):
def __init__(self, mark, material, weight_per_m, span, load):
super().__init__(mark, material, weight_per_m)
self.span = span; self.load = load
def moment(self):
return self.load * self.span**2 / 8
b = Beam("B1", "Steel", 80, 6.0, 25)
print(f"Moment: {b.moment():.1f} kNm, Weight: {b.total_weight(b.span):.1f} kg")
# P4
class Project:
def __init__(self, name):
self.name = name
self.beams = []
def add_beam(self, beam):
self.beams.append(beam)
def average_span(self):
return sum(b.span for b in self.beams) / len(self.beams) if self.beams else 0
proj = Project("Office Building")
proj.add_beam(Beam("B1", "Steel", 80, 6.0, 25))
proj.add_beam(Beam("B2", "Steel", 80, 4.5, 18))
proj.add_beam(Beam("B3", "Steel", 80, 7.2, 30))
print(f"Average span: {proj.average_span():.2f} m")
5. Applied Challenge Task
Task: Building Information Model (BIM) Lite – Room & Space Manager
Design a set of classes to model a simple building:
Spaceclass:- Attributes:
name,length,width,height,finish_floor_type(string). - Methods:
area(),volume(),__str__().
- Attributes:
Floorclass:- Attributes:
level_number,name,height_ff(floor‑to‑floor height). - Stores a list of
Spaceobjects. - Methods:
add_space(space),total_area(),total_volume(),__str__().
- Attributes:
Buildingclass:- Attributes:
project_name,address,floorslist. - Methods:
add_floor(floor),total_area(),total_volume(),building_height(),summary()– prints a formatted report.
- Attributes:
Main script that:
- Creates a building with at least 2 floors and 3–4 spaces total.
- Asks the user for some data interactively (e.g., floor name, space dimensions).
- Prints a complete summary: total area, volume, number of spaces, floor count.
Why this matters:
This exercise models a very simple BIM structure. The same pattern (class → object hierarchy) is used in professional BIM frameworks like IfcOpenShell. Understanding OOP in this context prepares you for working with real BIM data later in the course (Day 19+).
6. Brief Review Summary
- A class defines a blueprint; an object is an instance of that class.
__init__initialises attributes when an object is created.- Methods are functions that belong to the object; they access data via
self. __str__controls howprint()displays the object.- OOP organises data and behaviour together – mirroring real‑world AEC components.
- You can create hierarchies of objects (e.g., Building → Floors → Rooms).
Key takeaway:
OOP transforms your code from a collection of functions and data into a model of the building itself. This makes your AEC scripts more intuitive, maintainable, and scalable.
7. Preview of Next Topic (Day 15)
Tomorrow is the Weekly Mini‑Project for Phase 2.
You’ll build a Parametric Component Generator – a script that, given a span, generates a standard truss geometry and writes the coordinates to a CSV for import into CAD.
This will consolidate:
- Functions (Day 5)
- Lists and tuples (Day 6)
- Dictionaries (Day 7)
- String formatting (Day 8)
- File I/O (Day 9)
- List comprehensions (Day 11)
- numpy geometry (Day 13)
- Classes and OOP (Day 14)
Get ready to build a professional‑grade parametric design tool!
Subscribe to our Newsletter
Get updates delivered directly to your inbox.

Comments
Post a Comment