by Fedor Iskhakov, ANU

Description: Object oriented programming in modeling consumer choice model.

Consider the following model of a bundle goods market. A bundle of goods is a collection of particular items offered at a specified price. For example, Happy Meals at McDonalds is a set of items in a meal sold for a particular price.

One other example of bundled goods - subscription packages in theaters, for example La Scala in Milan or Mariinsky in St.Petersburg.

In this task you will write code to implement and operationalize this setup.

Develop the Python class to represent a bundle good with the following specifications:

- The class attribute (common to all objects of this class) is a list of goods
- The public property is a vector of integers defining how many of each goods are in the bundle
- The other property is the price for that bundle

The following arithmetic operations are defined for the bungles:

- addition:
- sum of two bundles is a bundle with added up items and prices
- sum of a bundle and a number (float or int) increases the price

- subtraction:
- difference between two bundles should produce a bundle with

- subtracting a number (float or int) from a bundle should only

- multiplication is only defined for bundle and an integers, and results in the bundle with all items multiplied by this number, and price increased by the same number
- devision is only defined for integers, and only such that the all quantities are divisible by this integer, the resulting bundle is a fraction of the original, with the price also decreased by the same number

Complete the class definition code, and run the tests in the next cell.

In [ ]:

```
class bundle_good():
'''Class of bundled goods with well defined arithmetics'''
items = ('Opera A', 'Opera B', \
'Ballet A', 'Ballet B', \
'Symphonic orchestra concert', \
'Rock opera', \
'Operetta') # 7 different goods
def __init__(self,quantities=[0,],price=0.0):
'''Creates the bundle good object, empty by default'''
pass
# ignore extra quantities if passed
# add zeros for the unspecified items
# ensure all quantities are integers
def __repr__(@@@):
'''String representation of the object'''
pass
def __add__(self,other):
'''Addition for bundle goods'''
pass
# if wrong type pass, raise the TypeError
# raise TypeError('Can only add bundle to bundle, or number to bundle price')
def __sub__(self,other):
'''Subtraction for bundles: subtract items and prices, or decrease price'''
pass
def __mul__(self,num):
'''Multiplication for bundles: proportional increase in nomenclature and price'''
pass
def __truediv__(self,num):
'''Division for bundles: fraction of the original bundle, only if quantities are divisable'''
pass
```

To make sure the class is running as it is supposed to, run all the tests below and confirm that the output is as expected.

In [ ]:

```
# Tests
x=bundle_good([1,2,3,4,5,6,7],11.43)
print(x) #should print "Bundle object [1, 2, 3, 4, 5, 6, 7] with price 11.43"
```

In [ ]:

```
x=bundle_good([1,2])
print(x) #should print "Bundle object [1, 2, 0, 0, 0, 0, 0] with price 0.00"
```

In [ ]:

```
x=bundle_good(range(25),100.2)
print(x) #should print "Bundle object [0, 1, 2, 3, 4, 5, 6] with price 100.20"
```

In [ ]:

```
x=bundle_good([1.5,2.3,3.2,4.1,5.75,6.86,7.97],1.43)
print(x) #should print "Bundle object [1, 2, 3, 4, 5, 6, 7] with price 1.43"
```

In [ ]:

```
x=bundle_good([1,2,3,4,5,6,7],11.43)
y=bundle_good([7,6,5,4,3,2,1],77.45)
z=x+y
print(z) #should print "Bundle object [8, 8, 8, 8, 8, 8, 8] with price 88.88"
```

In [ ]:

```
z=y-x
print(z) #should print "Bundle object [6, 4, 2, 0, -2, -4, -6] with price 66.02"
```

In [ ]:

```
z=x+4.531
print(z) #should print "Bundle object [1, 2, 3, 4, 5, 6, 7] with price 15.96"
```

In [ ]:

```
z=y-77
print(z) #should print "Bundle object [7, 6, 5, 4, 3, 2, 1] with price 0.45"
```

In [ ]:

```
z=x*11
print(z) #should print "Bundle object [11, 22, 33, 44, 55, 66, 77] with price 125.73"
```

In [ ]:

```
try:
z=x*11.5 #should raise a TypeError
except TypeError:
print("Ok 1") #should print "Ok 1"
```

In [ ]:

```
try:
z=x*y #should raise a TypeError
except TypeError:
print("Ok 2") #should print "Ok 2"
```

In [ ]:

```
try:
z=x/y #should raise a TypeError
except TypeError:
print("Ok 3") #should print "Ok 3"
```

In [ ]:

```
z=(x+y)/8
print(z) #should print "Bundle object [1, 1, 1, 1, 1, 1, 1] with price 11.11"
```

In [ ]:

```
try:
(x+y)/7 #should raise a ValueError
except ValueError:
print("Ok 4") #should print "Ok 4"
```

In [ ]:

```
z=x*15-y*2
print(z) #should print "Bundle object [1, 18, 35, 52, 69, 86, 103] with price 16.55"
```

In [ ]:

```
class bundle_good():
'''Class of bundled goods with well defined arithmetics'''
items = ('Opera A', 'Opera B', \
'Ballet A', 'Ballet B', \
'Symphonic orchestra concert', \
'Rock opera', \
'Operetta') # 7 different goods
def __init__(self,quantities=[0,],price=0.0):
'''Creates the bundle good object
'''
n = len(bundle_good.items) # number of available items
if len(quantities)<n:
# add zeros for the unspecified items
quantities += [0,]*(n-len(quantities))
elif len(quantities)>n:
# ignore extra numbers
quantities = quantities[0:n]
# create public attributes
# ensure the quantities in the object are integer
self.quantities=[int(x) for x in quantities]
self.price=price
def __repr__(self):
'''String representation of the object
'''
return 'Bundle object %r with price %1.2f' % (self.quantities,self.price)
def __add__(self,other):
'''Addition for bundles: add items and sum prices, or increase price
'''
if type(other) is bundle_good:
# add the quantities using list comprehension with one-to-one matching (zip)
q1 = [x+y for x,y in zip(self.quantities, other.quantities)]
# sum of the prices
p1 = self.price + other.price
# return new bundle
return bundle_good(quantities=q1,price=p1)
elif type(other) in (float,int):
# increase the price
p1 = self.price + other
# return new bundle
return bundle_good(quantities=self.quantities,price=p1)
else:
raise TypeError('Can only add bundle to bundle, or number to bundle price')
def __sub__(self,other):
'''Subtraction for bundles: subtract items and prices, or decrease price
'''
if type(other) is bundle_good:
# subtract the quantities using list comprehension with one-to-one matching (zip)
q1 = [x-y for x,y in zip(self.quantities, other.quantities)]
# sum of the prices
p1 = self.price - other.price
# return new bundle
return bundle_good(quantities=q1,price=p1)
elif type(other) in (float,int):
# decrease the price
p1 = self.price - other
# return new bundle
return bundle_good(quantities=self.quantities,price=p1)
else:
raise TypeError('Can only subtract bundle from bundle, or number from bundle price')
def __mul__(self,num):
'''Multiplication for bundles: repetition of the original bundle
'''
if type(num) is int:
# multiply quantities using list comprehension
q1 = [x * num for x in self.quantities]
# multiply the price
p1 = self.price * num
# return new bundle
return bundle_good(price=p1,quantities=q1)
else:
raise TypeError('Can only multiply bundle by an integer')
def __truediv__(self,num):
'''Division for bundles: fraction of the original bundle, only if quantities are devisable
'''
if type(num) is int:
# divide quantities and check for divisibility
q1 = [q//num for q in self.quantities]
if not all(q%num==0 for q in self.quantities):
# if can not be devided without a remainder, raise ValueError
raise ValueError('Can not divide bundle into fractional parts')
# divide the price
p1=self.price / num
# return new bundle
return bundle_good(price=p1,quantities=q1)
else:
raise TypeError('Can only divide bundle by an integer')
```