Chapter 8 Composition and Inheritance
8.1 Setup
from pathlib import Path
= Path.cwd() / 'composition_inheritance'
pkgpath str(pkgpath)])
sys.path.extend([from composition_inheritance import market as mk
from composition_inheritance import consumer_noinheritance as cNoInherit
from composition_inheritance import consumer_inheritance as cInherit
In Python, each .py file represents a module. When multiple .py files
are inside a folder with a __init__.py
file, the folder forms a
package.
8.2 Market
= mk.Demand
Demand = mk.Supply
Supply = mk.Market
Market = 100, 1, -100, 5 a, b, c, d
8.2.1 Composition (Has-A Relation)
Market has
- a demand:
\[Q_d(p) = a - b\times p + \epsilon\]
- a supply
\[Q_s(p) = c + d\times p + u,\] where \(\epsilon\) and \(u\) are aggregate shocks. Different markets have different \((a,b,c,d)\) but faces the same \((\epsilon, u)\).
And has, in theory,
- an equilibrium condition where demand equals to supply so that
\[ \begin{align} p^* &=[(a-c)+(\epsilon-u)]/(b+d)\\ q^* &= Q_d(p^*) \end{align} \]
Assume a/b (demand y-intercept), -c/d (supply y-intercept) satisfies \(a/b > -c/d\).
Figure 8.1: Composition
In the following example, we set \(a=100, b=1\) and \(c=-100, d=5\)
8.2.2 Demand
Figure 8.2: Demand. (*: instance variable, ** : class variable, +: instance method, ++: class method)
What a demand object (instance) is like:
= Demand(100, 1)
demand0 # keep track of fundamental parameters
demand0.a
demand0.b# can compute quantity demanded at a price
15)
demand0.Q(
# when aggregate shock changes, all demands change at the same time
= Demand(150, 2)
demand1 15)
demand1.Q(= 5
Demand.epsilon 15)
demand0.Q(15)
demand1.Q(= 0 Demand.epsilon
Figure 8.4
class Demand:
# aggregate demand shock
= 0
epsilon # for each market's demand:
def __init__(self, a, b):
self.a=a
self.b=b
def Q(self, p):
= self.a, self.b
a, b return a - b*p + self.__class__.epsilon
= Demand(a, b)
demand1 5)
demand1.Q(= 10
Demand.epsilon 5) demand1.Q(
8.2.3 Supply
Figure 8.3: Supply. (*: instance variable, ** : class variable, +: instance method, ++: class method)
What a supply object (instance) is like:
= Supply(100, 1)
supply0 # keep track of fundamental parameters
supply0.c
supply0.d# can compute quantity supplyed at a price
25)
supply0.Q(
# when aggregate shock changes, all supplys change at the same time
= Supply(150, 2)
supply1 25)
supply1.Q(= 5
Supply.epsilon 25)
supply0.Q(25)
supply1.Q(= 0 Supply.epsilon
class Supply:
# aggregate supply shock
= 0
u # for each market's supply:
def __init__(self, c, d):
self.c=c
self.d=d
def Q(self, p):
= self.c, self.d
c, d return c + d*p + self.__class__.u
8.2.4 Market
Figure 8.4: Market. (*: instance variable, ** : class variable, +: instance method, ++: class method)
class Market:
# attributes (properties) for each market:
def __init__(self, a, b, c, d):
# has it's own demand and supply (objects)
self.demand = Demand(a, b)
self.supply = Supply(c, d)
# functions (mechanism) for each market
def equilibrium(self):
= self.demand.a, self.demand.b, self.supply.c, self.supply.d
a, b, c, d = ((a-c)+Demand.epsilon-Supply.u)/(b+d)
p = self.demand.Q(p)
q self.p, self.q = p, q
return self
= Market(a, b, c, d)
market1 3)
market1.demand.Q(3)
market1.supply.Q(
market1.equilibrium().p market1.equilibrium().q
Note that the instance method .equilibrium
has a return of self
.
This is why we can chain the computation and outcome:
market1.equilibrium().p
8.3 Consumers
8.3.1 Two types
Cobb-Douglas: \[U(x_1, x_2)=x_1^{\alpha}x_2^{1-\alpha}\]
Leontief: \[U(x_1, x_2)=\min(\alpha x_1, (1-\alpha) x_2)\] with \(0<\alpha<1\).
Consumer with Cobb-Douglass preference is a consumer.
Consumer with Leontief preference is also a consumer.
All consumers:
have income (heterogeneous)
face market prices (homogeneous)
face budget constraint
Figure 8.5: Two consumer types. (*: instance variable, ** : class variable, +: instance method, ++: class method)
= cNoInherit.Consumer_cobbDouglas
Consumer_cobbDouglas = cNoInherit.Consumer_leontief Consumer_leontief
class Consumer_cobbDouglas:
= [1, 1] # all face market prices, suppose two markets.
p def __init__(self, income):
self.alpha = alpha
self.income = income # all have income
def bc(self, x): # all face budget constraint
= self.__class__.p
p1, p2 = x
x1, x2 return self.income - p1*x1 - p2*x2
def utility(self, x):
= x
x1, x2 return x1**self.alpha * x2**(1-self.alpha)
class Consumer_leontief:
= [1, 1] # all face market prices, suppose two markets.
p def __init__(self, income):
self.alpha = alpha
self.income = income # all have income
def bc(self, x): # all face budget constraint
= self.__class__.p
p1, p2 = x
x1, x2 return self.income - p1*x1 - p2*x2
def utility(self, x):
= x
x1, x2 return min(self.alpha*x1, (1-self.alpha)*x2)
= cNoInherit.Consumer_cobbDouglas
Consumer_cobbDouglas = cNoInherit.Consumer_leontief Consumer_leontief
8.3.2 Inheritance (Is-A relation)
Note that
All consumers:
have income (heterogeneous)
face market prices (homogeneous)
face budget constraint
Figure 8.6: Two consumer types inherit a super class Consumer. (*: instance variable, ** : class variable, +: instance method, ++: class method)
For all consumers
class Consumer:
= [1, 1] # all face market prices, suppose two markets.
p = []
all_consumers def __init__(self, income):
self.income = income # all have income
self.__class__.all_consumers.append(self)
def bc(self, x): # all face budget constraint
= self.__class__.p
p1, p2 = x
x1, x2 return self.income - p1*x1 - p2*x2
- Here we embed an instances collector
all_consumers
(**).
\[U(x1, x2)=x1^{\alpha}*x2^{1-\alpha},\ 0<\alpha<1\]
class Consumer_cobbDouglas(Consumer):
def __init__(self, alpha, income):
super().__init__(income)
self.alpha = alpha
def utility(self, x):
= x
x1, x2 return x1**self.alpha * x2**(1-self.alpha)
super().__init__(...)
will make subclass (Consumer_cobbDouglass)
inherit the interface income (ie. subclass_instance.income
exists)
as its instance variable.
Class variables from superclass will be inherited automatically without
calling super()
.
class A:
=1
c1def __init__(self, x):
self.x=x
class B(A):
def __init__(self, y):
self.y=y
= B(3)
b
b.c1# Inheritance without inheriting instance variable is not recommended since it ruins the relationship definition between superclass and subclass.
# If b instance does not need x instance variable, then A class should be defined without x instance.
class A:
=1
c1
class B(A):
def __init__(self, y):
self.y = y
= B(3)
b b.c1
\[U(x1, x2)=\min(\alpha*x1, (1-\alpha)*x2), \ 0<\alpha<1\]
class Consumer_leontief(Consumer):
def __init__(self, alpha, income):
self.alpha = alpha
super().__init__(income)
def utility(self, x):
= x
x1, x2 return min(self.alpha*x1, (1-self.alpha)*x2)
= cInherit.Consumer
Consumer = cInherit.Consumer_cobbDouglas
Consumer_cobbDouglas = cInherit.Consumer_leontief Consumer_leontief
= Consumer_cobbDouglas(0.3, 500)
consumer_cb1 = Consumer_leontief(0.7, 700)
consumer_lt1
# all consumers
## face market prices
consumer_cb1.p
consumer_lt1.p## have income
consumer_cb1.income
consumer_lt1.income## face budget constraint
200, 100])
consumer_cb1.bc([200, 500])
consumer_lt1.bc([
## utilities
200, 100])
consumer_cb1.utility([200, 500])
consumer_lt1.utility([
## check all consumers
Consumer.all_consumers
Consumer is called a
* super class, parent class, or base class of
Consumer_cobbDouglas/Consumer_leontief.
Consumer_cobbDouglas/Consumer_leontief is a
* derived class, child class, or extended class of Consumer. In
most applications, only child class are essential objects. Why do we
want to build from a parent class instead of the ultimate end class in
one stop?
easy to maintain.
easy to extend.
When an instance has income instance variable, market prices class variable and budget constraint instance method. This instance is a consumer.
When it walks like a duck, quacks like a duck, it must be a duck
8.3.3 Hierachy of inheritance: rationing constraint
There are some consumers living in the area where \(x_2\) are rationed. No one can buy more than \(2\) units of \(x_2\).
Figure 8.7: Inheritance hierarchy. (*: instance variable, ** : class variable, +: instance method, ++: class method)
class ConsumerRation(Consumer):
def __init(self, income):
super().__init__(income)
@staticmethod
def ration_constraint(x):
= x
x1, x2 return 2-x2
class ConsumerRation_cd(ConsumerRation):
def __init__(self, alpha, income):
super().__init__(income)
self.alpha = alpha
def utility(self, x):
= x
x1, x2 return x1**self.alpha * x2**(1-self.alpha)
class ConsumerRation_lt(ConsumerRation):
def __init__(self, alpha, income):
super().__init__(income)
self.alpha = alpha
def utility(self, x):
= x
x1, x2 return min(self.alpha*x1, (1-self.alpha)*x2)
= ConsumerRation_cd(0.3, 500)
consumerRation_cd1 = ConsumerRation_lt(0.3, 700)
consumerRation_lt1 2,3])
consumerRation_cd1.ration_constraint([2,3]) consumerRation_lt1.ration_constraint([
8.4 Mixing composition and inheritance
Utility function can be seen as a component of all consumers:
class Utility_cobbDouglas:
def __init__(self, alpha):
self.alpha = alpha
def utility(self, x):
= x
x1, x2 = self.alpha
alpha return x1**alpha*x2**(1-alpha)
class Consumer_cobbDouglas(Consumer):
def __init__(self, alpha, income):
super().__init__(income)
self.alpha = alpha
self.utilityComponent = Utility_cobbDouglas(self.alpha)
def utility(self, x):
return self.utilityComponent.utility(x)
= Utility_cobbDouglas(0.3)
u_cb1 2,3])
u_cb1.utility([
= Consumer_cobbDouglas(0.3, 500)
cb1 2,3]) cb1.utility([
Why component? \[U(x_1, x_2) = x_1^{\alpha+\eta}x_2^{1-\alpha-\eta}\]
U
8.5 Download
from pathlib import Path
import requests
= requests.get("https://www.dropbox.com/s/85t567gerqbbso0/composition_inheritance.py?dl=1")
response = Path.cwd() / 'composition_inheritance.py'
filepath filepath.write_text(response.text)
= Path.cwd() / 'composition_inheritance'
pkgpath str(pkgpath)])
sys.path.extend([from composition_inheritance import market as mk
from composition_inheritance import consumer_noinheritance as cInherit
from composition_inheritance import consumer_inheritance as cNoInherit
8.6 Exercise
8.6.1 2. Constraint
Budget constraint and rationing constraint can also be component that derived from a class call Constraint. Define Constraint class and modify your consumer classes accordingly.
::opts_chunk$set(message=F, eval=F)
knitr::klippy(lang=c("r","python")) klippy
1. Social welfare