@egges , I follow your video avidly. Thanks ! Have a design related question :
I have a dataclass of a single class object 'AStock' as such:
@dataclass
class AStock:
code_: Union[str, int]
force_update_: bool = False
ticker_: str = field(init=False)
symbol_: str = field(init=False)
name_: str = field(init=False)
sector_: str = field(init=False)
subsector_: str = field(init=False)
@exception(logger)
def __post_init__(self) -> None:
try:
self.code_ = str(self.code_).zfill(4)
self.ticker_ = indexer(code=self.code_, arg='ticker')
self.symbol_ = indexer(code=self.code_, arg='symbol')
self.name_ = indexer(code=self.code_, arg='full_name')
self.sector_ = indexer(code=self.code_, arg='sector')
self.subsector_ = indexer(code=self.code_, arg='subsector')
except NoStockFound:
raise
except Exception as e:
raise StockException(stock=self) from e
What I want to achieve is to create a class object that would initialize a single stock object or a collection of stock objects. So I did a 'Stocks' and a 'Stock' object.
'Stocks' here initializes a group of 'AStock' objects.
@dataclass
class Stocks:
code_: List[str]
force_update_: bool = False
ticker_: str = field(init=False)
symbol_: str = field(init=False)
name_: str = field(init=False)
sector_: str = field(init=False)
subsector_: str = field(init=False)
@exception(logger)
def __post_init__(self) -> None:
self.ticker_ = [indexer(code, arg='ticker') for code in self.code_]
self.symbol_ = [indexer(code, arg='symbol') for code in self.code_]
self.name_ = [indexer(code, arg='full_name') for code in self.code_]
self.sector_ = [indexer(code, arg='sector') for code in self.code_]
self.subsector_ = [indexer(code, arg='subsector') for code in self.code_]
def __repr__(self) -> str:
return ', '.join([f'{i[0]}:{i[1]}' for i in list(zip(self.code_, self.ticker_))])
def __str__(self) -> str:
return ', '.join([f'{i[0]}:{i[1]}' for i in list(zip(self.code_, self.ticker_))])
and this 'Stock' object here is to handle the creation of 'AStock' or 'Stocks' object.
@dataclass
class Stock:
code: Union[str, int, List[str]]
force_update: bool = False
@exception(logger)
def __new__(cls, code, force_update: bool = False):
if type(code) in [str, int]:
return AStock(code, force_update)
elif type(code) in [list]:
return Stocks(code, force_update)
else:
raise ValueError('Not a valid stock code')
So for example:
If Stock(['1203', '1232'])
will create Stocks
object and Stock('1203')
will create a AStock
object. Just by providing arguments as a List or String it could detect whether to create AStock
for single stock or Stocks
for multiple stocks.
However, this is pretty 'hacky' way of using __new__
to return an either AStock
object or Stocks
object. Is there a more elegant way of doing this?