4.4 KiB
4.4 KiB
Exercise 3.4 - Solution
(a) Private attributes
# stock.py
class Stock:
= (str, int, float)
_types def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
@classmethod
def from_row(cls, row):
= [func(val) for func, val in zip(cls._types, row)]
values return cls(*values)
def cost(self):
return self.shares * self.price
def sell(self, nshares):
self.shares -= nshares
(b) Computed Attributes
# stock.py
class Stock:
= (str, int, float)
_types def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
@classmethod
def from_row(cls, row):
= [func(val) for func, val in zip(cls._types, row)]
values return cls(*values)
@property
def cost(self):
return self.shares * self.price
def sell(self, nshares):
self.shares -= nshares
(c) Enforcing Type-Checking Rules
# stock.py
class Stock:
= (str, int, float)
_types def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
@classmethod
def from_row(cls, row):
= [func(val) for func, val in zip(cls._types, row)]
values return cls(*values)
@property
def shares(self):
return self._shares
@shares.setter
def shares(self, value):
if not isinstance(value, int):
raise TypeError('Expected an integer')
if value < 0:
raise ValueError('shares must be >= 0')
self._shares = value
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if not isinstance(value, float):
raise TypeError('Expected a float')
if value < 0:
raise ValueError('price must be >= 0')
self._price = value
@property
def cost(self):
return self.shares * self.price
def sell(self, nshares):
self.shares -= nshares
(d) Adding __slots__
# stock.py
class Stock:
__slots__ = ('name','_shares','_price')
= (str, int, float)
_types
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
@classmethod
def from_row(cls, row):
= [func(val) for func, val in zip(cls._types, row)]
values return cls(*values)
@property
def shares(self):
return self._shares
@shares.setter
def shares(self, value):
if not isinstance(value, int):
raise TypeError('Expected integer')
if value < 0:
raise ValueError('shares must be >= 0')
self._shares = value
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if not isinstance(value, float):
raise TypeError('Expected float')
if value < 0:
raise ValueError('price must be >= 0')
self._price = value
@property
def cost(self):
return self.shares * self.price
def sell(self, nshares):
self.shares -= nshares
(e) Reconciling types
# stock.py
class Stock:
__slots__ = ('name','_shares','_price')
= (str, int, float)
_types def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
@classmethod
def from_row(cls, row):
= [func(val) for func, val in zip(cls._types, row)]
values return cls(*values)
@property
def shares(self):
return self._shares
@shares.setter
def shares(self, value):
if not isinstance(value, self._types[1]):
raise TypeError(f'Expected {self._types[1].__name__}')
if value < 0:
raise ValueError('shares must be >= 0')
self._shares = value
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if not isinstance(value, self._types[2]):
raise TypeError(f'Expected {self._types[2].__name__}')
if value < 0:
raise ValueError('price must be >= 0')
self._price = value
@property
def cost(self):
return self.shares * self.price
def sell(self, nshares):
self.shares -= nshares