EE1021 Programming for Engineers · Lecture 7 · 2026–2027
__init__self during a method call__str__ and recognize other special methodsname = "sensor-1"
values = [20.0, 22.0]
name.upper() # method of a str object
values.append(24.0) # method of a list object
type(values) # <class 'list'>1234 is an instance of int; "hello" is an instance of strappend() is fastL[i], len(L), L.append()Coordinate is the class name and the new type; the indented block defines the typec and origin are two distinct instances of the same class.
__init__ Establishes Initial State__init__ — special method Python calls right after it creates the instance; double underscores mark it as special__init__ method; it runs automatically when an object is created, and this course uses the word constructor for itself — parameter that refers to the instance being initializedself.x, self.y — two data attributes stored on every Coordinate objectCoordinate(3, 4) — creates a new object and passes 3 and 4 to __init__; you never pass selfc.x — the dot accesses an attribute of instance cData attributes of an instance are called instance variables. Python runs __init__ conceptually as Coordinate.__init__(new_object, 3, 4).
What are c.x, c.y, origin.x, and origin.y now?
c.x is 10, c.y is 4; origin.x and origin.y remain 0. Each __init__ call filled a separate object.
selfLocal variables disappear
After __init__ returns, the object has no attributes.
A list written directly under class, outside __init__, is created once and shared by every object. Write self.readings = [] inside __init__ so each object gets its own list.
selfself — the instance the method is called onother — an ordinary parameter; here another Coordinateself.x, other.x — dot notation reads data from either objectTwo equivalent calls: c.distance(origin) and Coordinate.distance(c, origin). Python passes the receiver as self automatically.
self?In each call, which object is self and which is other? What is printed?
First call: self is b, other is a. Second call: the roles swap. Both print 5.0, because distance is symmetric.
class Battery:
def __init__(self, capacity_mah):
self.capacity_mah = capacity_mah
self.charge_mah = 0
def charge(self, amount_mah):
self.charge_mah = min(self.capacity_mah, self.charge_mah + amount_mah)
def level_percent(self):
return 100 * self.charge_mah / self.capacity_mahcharge is a command: it changes the receiver’s state and returns nothinglevel_percent is a query: it reports state and changes nothing__str__ Supplies a Readable InterfaceThe default text is uninformative. Define __str__; print calls it for you.
def __str__(self):
pct = self.level_percent()
return f"Battery {self.charge_mah}/{self.capacity_mah} mAh ({pct:.0f}%)"__str__ must return a string.
__str__What is wrong with this implementation, and what does print(pack) do?
It prints but returns None, and print(pack) raises TypeError: __str__ returned non-string. Replace the body with a return of an f-string.
__init__class Resistor:
def __init__(self, label, ohms):
if ohms <= 0:
raise ValueError("resistance must be positive")
self.label = label
self.ohms = ohmstry / except ValueError, exactly as in Lecture 6__init__ returns, every Resistor satisfies its contractclass Resistor:
def __init__(self, label, ohms):
if ohms <= 0:
raise ValueError("resistance must be positive")
self.label = label
self.ohms = ohms
def current(self, volts):
return volts / self.ohms
def power(self, volts):
return volts * self.current(volts)
def __str__(self):
return f"{self.label}: {self.ohms} ohm"power reuses self.current: methods call other methods through self.
assert Checks That Something Is Truex = 5
assert x > 0 # true: nothing happens
assert x > 10, "x is too small" # false: the program stopsassert condition, "message" states something you expect to be trueAssertionError and prints your messageassert in tests; check user input with if and raise, as in Lecture 6r1 = Resistor("R1", 220)
r2 = Resistor("R2", 1000)
assert r1.current(5) == 5 / 220
assert r2.current(5) == 0.005
assert str(r1) == "R1: 220 ohm"
try:
Resistor("R3", 0)
except ValueError:
print("invalid resistor rejected")Test normal values, a boundary, an invalid construction, and that one instance does not disturb another.
print, +, -, ==, <, len() each look for a special method| special method | expression it implements |
|---|---|
__str__(self) |
print(self), str(self) |
__add__(self, other) |
self + other |
__sub__(self, other) |
self - other |
__eq__(self, other) |
self == other |
__lt__(self, other) |
self < other |
__len__(self) |
len(self) |
+ on a Fraction Typeclass Fraction:
def __init__(self, num, denom):
self.num = num
self.denom = denom
def __str__(self):
return f"{self.num}/{self.denom}"
def __add__(self, other):
top = self.num * other.denom + self.denom * other.num
bottom = self.denom * other.denom
return Fraction(top, bottom)__add__ returns a new Fraction; neither operand changes.
type() and isinstance() Report the Class>>> c = Coordinate(3, 4)
>>> type(c)
<class '__main__.Coordinate'>
>>> isinstance(c, Coordinate)
True
>>> type(Coordinate)
<class 'type'>type(c) is the class you wroteisinstance checks membership and is the safe way to test an object’s typetypeA Motor has a name and a maximum speed in rpm. set_speed(rpm) stores a speed and rejects values above the maximum or below zero. It prints as M1: 1500/3000 rpm.
Identify:
Parameters: name, max rpm. Attributes: name, max rpm, current speed (starts at 0). set_speed raises ValueError outside 0 … max. __str__ builds the string. Tests: set_speed(1500) then str(m); set_speed(5000) inside try/except.
Add to Coordinate and test:
Then explain which object becomes self in origin.move(1, 2), and whether move is a command or a query.
Body: self.x += dx and self.y += dy. In origin.move(1, 2), self refers to the object referenced by origin. It is a command: it changes state and returns None.
__init__ establishes valid initial attributes and may reject invalid onesself is the receiver object during a method call__str__, __add__, and other special methods connect your type to Python syntaxIn the lab you apply all of this to a new type, a Sensor with readings, that you build and test from a contract.