From closure-based state to message passing and data-directed dispatch
nonlocal updates enclosing bindingsdef make_account(holder, balance=0):
"""Return a dispatch function representing an account."""
def deposit(amount):
nonlocal balance
balance += amount
return balance
def withdraw(amount):
nonlocal balance
if amount > balance:
return 'Insufficient funds'
balance -= amount
return balance
def dispatch(message):
if message == 'holder':
return holder
if message == 'balance':
return balance
if message == 'deposit':
return deposit
if message == 'withdraw':
return withdraw
raise ValueError('Unknown message')
return dispatch
# Example usage
acc = make_account('Alice', 100)
print(acc('holder'))
print(acc('deposit')(25))
print(acc('withdraw')(70))
print(acc('balance'))
'deposit', 'withdraw'nonlocal balance inside methodsAccount: __init__ and selfclass Account:
"""A simple bank account."""
def __init__(self, holder, balance=0):
self.holder = holder
self.balance = balance
def deposit(self, amount):
self.balance += amount
return self.balance
def withdraw(self, amount):
if amount > self.balance:
return 'Insufficient funds'
self.balance -= amount
return self.balance
# Example usage
acc = Account('Bob', 50)
print(acc.deposit(20))
print(acc.withdraw(10))
print(acc.balance)
__init__(self, ...): initialize instance attributesself: the instance being operated onacc.holder, acc.balanceacc.deposit(20) changes acc.balanceclass Demo:
def __init__(self, x):
self.x = x
def add_to_x(self, amount):
self.x += amount
return self.x
obj = Demo(10)
# Two equivalent calls:
print(obj.add_to_x(5))
print(Demo.add_to_x(obj, 5))
obj.method(arg) rewrites to Class.method(obj, arg)obj.method carries obj as the first argumentobj is a name; the instance is a valueclass SavingsAccount:
interest = 0.02 # class variable
def __init__(self, holder, balance=0):
self.holder = holder
self.balance = balance # instance variable
def yearly_yield(self):
return self.balance * self.interest
s1 = SavingsAccount('Ana', 100)
s2 = SavingsAccount('Ben', 100)
print(s1.yearly_yield())
SavingsAccount.interest = 0.05
print(s2.yearly_yield())
s1.interest = 0.08 # shadows the class attribute for s1 only
print(s1.yearly_yield())
print(s2.yearly_yield())
SavingsAccount.interest shared defaultself.balance unique per instanceSavingsAccount.interest = ... affects all instances (unless shadowed)s1.interest = ... creates per-instance overrideclass Account:
def __init__(self, holder, balance=0):
self.holder = holder
self.balance = balancedef deposit(self, amount):
self.balance += amount
return self.balancedef withdraw(self, amount):
if amount > self.balance:
return 'Insufficient funds'
self.balance -= amount
return self.balanceclass CheckingAccount(Account):
withdrawal_fee = 1CheckingAccount(Account): inherits methods and attributeswithdraw adds fee, then calls super().withdraw(...)ch.withdraw(amount)super() = start search at the parent linkclass A:
x = "A"
class B(A):
pass
class C(A):
x = "C"
class D(B, C):
pass
print(D.x) # "C"
print(D.__mro__)
import math# --- Tag machinery ---
def attach_tag(tag, contents):
return (tag, contents)def type_tag(datum):
return datum[0]def contents(datum):
return datum[1]'rect' vs 'polar'real_part(z) works for both tagsput(...), not by editing selectorsisinstance, methods, or tables?if isinstance(x, T): ... (easy, not additive)x.add(y) (polymorphism, duck typing)apply_generic(op, x, y) (SICP 2.4/2.5)ch = CheckingAccount('Eve', 10) then ch.withdrawal_fee = 5 then ch.withdraw(3) then print(ch.balance)?apply_generic) over inheritance (super())?
Powered by SciMigo AI Tutor - https://scimigo.com