159 lines
6.2 KiB
Python
159 lines
6.2 KiB
Python
|
"""
|
|||
|
https://stepik.org/lesson/701990/step/10?unit=702091
|
|||
|
|
|||
|
В программе необходимо объявить классы для работы с кошельками в разных валютах:
|
|||
|
MoneyR - для рублевых кошельков
|
|||
|
MoneyD - для долларовых кошельков
|
|||
|
MoneyE - для евро-кошельков
|
|||
|
|
|||
|
Объекты этих классов могут создаваться командами:
|
|||
|
rub = MoneyR() # с нулевым балансом
|
|||
|
dl = MoneyD(1501.25) # с балансом в 1501.25 долларов
|
|||
|
euro = MoneyE(100) # с балансом в 100 евро
|
|||
|
>>> rub = MoneyR()
|
|||
|
>>> dl = MoneyD(1501.25)
|
|||
|
>>> euro = MoneyE(100)
|
|||
|
>>> rub.volume, dl.volume, euro.volume
|
|||
|
(0, 1501.25, 100)
|
|||
|
|
|||
|
В каждом объекте этих классов должны формироваться локальные атрибуты:
|
|||
|
__cb - ссылка на класс CentralBank (центральный банк, изначально None);
|
|||
|
__volume - объем денежных средств в кошельке (если не указано, то 0).
|
|||
|
|
|||
|
Также в классах MoneyR, MoneyD и MoneyE должны быть объекты-свойства (property) для работы с локальными атрибутами:
|
|||
|
cb - для изменения и считывания данных из переменной __cb;
|
|||
|
volume - для изменения и считывания данных из переменной __volume.
|
|||
|
|
|||
|
Объекты классов должны поддерживать следующие операторы сравнения:
|
|||
|
rub < dl
|
|||
|
dl >= euro
|
|||
|
rub == euro # значения сравниваются по текущему курсу центрального банка с погрешностью 0.1 (плюс-минус)
|
|||
|
euro > rub
|
|||
|
При реализации операторов сравнения считываются соответствующие значения __volume из сравниваемых объектов и приводятся к рублевому эквиваленту в соответствии с курсом валют центрального банка.
|
|||
|
|
|||
|
Чтобы каждый объект классов MoneyR, MoneyD и MoneyE "знал" текущие котировки, необходимо в программе объявить еще один класс CentralBank.
|
|||
|
Объекты класса CentralBank создаваться не должны (запретить), при выполнении команды:
|
|||
|
>>> CentralBank()
|
|||
|
|
|||
|
должно просто возвращаться значение None. А в самом классе должен присутствовать атрибут:
|
|||
|
|
|||
|
rates = {'rub': 72.5, 'dollar': 1.0, 'euro': 1.15}
|
|||
|
>>> CentralBank.rates
|
|||
|
{'rub': 72.5, 'dollar': 1.0, 'euro': 1.15}
|
|||
|
|
|||
|
Здесь числа (в значениях словаря) - курс валюты по отношению к доллару.
|
|||
|
|
|||
|
Также в CentralBank должен быть метод уровня класса:
|
|||
|
register(cls, money) - для регистрации объектов классов MoneyR, MoneyD и MoneyE.
|
|||
|
|
|||
|
При регистрации значение __cb объекта money должно ссылаться на класс CentralBank.
|
|||
|
Через эту переменную объект имеет возможность обращаться к атрибуту rates класса CentralBank и брать нужные котировки.
|
|||
|
|
|||
|
Если кошелек не зарегистрирован, то при операциях сравнения должно генерироваться исключение:
|
|||
|
raise ValueError("Неизвестен курс валют.")
|
|||
|
Пример использования классов (эти строчки в программе писать не нужно):
|
|||
|
|
|||
|
>>> CentralBank.rates = {'rub': 72.5, 'dollar': 1.0, 'euro': 1.15}
|
|||
|
>>> r = MoneyR(45000)
|
|||
|
>>> d = MoneyD(500)
|
|||
|
>>> CentralBank.register(r)
|
|||
|
>>> CentralBank.register(d)
|
|||
|
>>> r > d, r.value, d.value
|
|||
|
(True, 620.6896551724138, 500.0)
|
|||
|
|
|||
|
if r > d:
|
|||
|
print("неплохо")
|
|||
|
else:
|
|||
|
print("нужно поднажать")
|
|||
|
|
|||
|
>>> r2 = MoneyR(100)
|
|||
|
>>> r2 > r
|
|||
|
Traceback (most recent call last):
|
|||
|
...
|
|||
|
ValueError: Неизвестен курс валют.
|
|||
|
|
|||
|
P.S. В программе на экран ничего выводить не нужно, только объявить классы.
|
|||
|
"""
|
|||
|
|
|||
|
from functools import total_ordering
|
|||
|
|
|||
|
|
|||
|
class CentralBank:
|
|||
|
rates = {"rub": 72.5, "dollar": 1.0, "euro": 1.15}
|
|||
|
|
|||
|
def __new__(self):
|
|||
|
...
|
|||
|
|
|||
|
@classmethod
|
|||
|
def register(cls, obj):
|
|||
|
obj.register_cb(cls)
|
|||
|
|
|||
|
|
|||
|
@total_ordering
|
|||
|
class Wallet:
|
|||
|
currency: str
|
|||
|
|
|||
|
def __repr__(self):
|
|||
|
return f"{self.__class__.__name__}({self.volume!r})"
|
|||
|
|
|||
|
def register_cb(self, cb: type):
|
|||
|
self.cb = cb
|
|||
|
|
|||
|
def __init__(self, volume=0):
|
|||
|
self.cb = None
|
|||
|
self.volume = volume
|
|||
|
|
|||
|
def __eq__(self, other):
|
|||
|
if hasattr(other, "value"):
|
|||
|
return abs(self.value - other.value) <= 0.1
|
|||
|
return NotImplemented
|
|||
|
|
|||
|
def __lt__(self, other):
|
|||
|
if hasattr(other, "value"):
|
|||
|
return abs(self.value - other.value) > 0.1 and self.value < other.value
|
|||
|
return NotImplemented
|
|||
|
|
|||
|
@property
|
|||
|
def cb(self):
|
|||
|
return getattr(self, f"_{self.__class__.__name__}__cb")
|
|||
|
|
|||
|
@cb.setter
|
|||
|
def cb(self, value):
|
|||
|
setattr(self, f"_{self.__class__.__name__}__cb", value)
|
|||
|
|
|||
|
@property
|
|||
|
def volume(self):
|
|||
|
return getattr(self, f"_{self.__class__.__name__}__volume")
|
|||
|
|
|||
|
@volume.setter
|
|||
|
def volume(self, value):
|
|||
|
setattr(self, f"_{self.__class__.__name__}__volume", value)
|
|||
|
|
|||
|
@property
|
|||
|
def rate(self):
|
|||
|
if not self.cb:
|
|||
|
raise ValueError("Неизвестен курс валют.")
|
|||
|
return self.cb.rates[self.currency]
|
|||
|
|
|||
|
@property
|
|||
|
def value(self):
|
|||
|
return self.volume / self.rate
|
|||
|
|
|||
|
|
|||
|
class MoneyR(Wallet):
|
|||
|
currency = "rub"
|
|||
|
|
|||
|
|
|||
|
class MoneyD(Wallet):
|
|||
|
currency = "dollar"
|
|||
|
|
|||
|
|
|||
|
class MoneyE(Wallet):
|
|||
|
currency = "euro"
|
|||
|
|
|||
|
|
|||
|
if __name__ == "__main__":
|
|||
|
import doctest
|
|||
|
|
|||
|
doctest.testmod()
|