Напишите программу для расчета баланса кредитной карты через год, если человек платит только минимальный ежемесячный платеж, требуемый компанией-эмитентом кредитной карты каждый месяц.
Следующие переменные содержат значения, как описано ниже:
balance— непогашенный остаток по кредитной карте
annualInterestRate— годовая процентная ставка в виде десятичной дроби
monthlyPaymentRate— минимальная ежемесячная ставка платежа в виде десятичной дробиЗа каждый месяц рассчитывайте выписки по ежемесячному платежу и остатку. По истечении 12 месяцев распечатайте остаток. Обязательно распечатайте не более двух десятичных знаков точности — так что печатайте
Remaining balance: 813.41вместо
Remaining balance: 813.4141998135Таким образом, ваша программа выводит только одно: остаток на конец года в формате:
Remaining balance: 4784.0Краткое изложение требуемой математики можно найти ниже:
begin {align *} text {Ежемесячная процентная ставка} & = frac { text {Годовая процентная ставка}} {12} \ text {Минимальный ежемесячный платеж} & = text {Минимальная ежемесячная ставка платежа} times text {Предыдущий остаток} \ text {Ежемесячный невыплаченный остаток} & = text {Предыдущий остаток} \ & — text {Минимальный ежемесячный платеж} \ text {Обновляемый остаток каждый месяц} & = text {Ежемесячно невыплаченный остаток} \ & + ( text {Ежемесячная процентная ставка} times text {Ежемесячный невыплаченный остаток}) end {align *}
Код
def balances(initial_balance, annual_interest_rate, minimum_monthly_payment_rate):
balance = initial_balance
monthly_interest_rate = annual_interest_rate / 12
for month in range(13):
minimum_monthly_payment = balance * minimum_monthly_payment_rate
monthly_unpaid_balance = balance - minimum_monthly_payment
yield {'month': month,
'minimum_monthly_payment': minimum_monthly_payment,
'balance': balance}
balance = monthly_unpaid_balance + (monthly_unpaid_balance * monthly_interest_rate)
def main():
*bs, remaining_balance = balances(balance, annualInterestRate, monthlyPaymentRate)
print('Remaining Balance: {}'.format(round(remaining_balance['balance'], 2)))
# Testing data
balance = 484
annualInterestRate = .2
monthlyPaymentRate = .04
## ifname_main does not work in grader
if __name__ == '__main__':
main()
Заранее спасибо.
2 ответа
- Можно использовать подсказки типа PEP484
range(13)неудобно — нет смысла возвращать начальный баланс, поэтому просто выведите скорректированные остатки и сделайте это 12 раз- Нет смысла сдавать месяц, платеж и баланс; просто уступите баланс. Даже если вам нужно было найти все три, словарь — не лучший способ сделать это. Кортежи стандартные; или класс данных лучше структурирован.
- Не надо звонить
formatили жеround. Просто используйте.2f. Обратите внимание, что это противоречит спецификацииRemaining balance: 4784.0но это глупо; это денежная сумма, поэтому точность должна быть фиксированной. - Ваш
balancesхорош как генератор, но зачем ограничивать его до 12 итераций? Более общая и полезная реализация просто повторяется бесконечно. Использоватьisliceвывести 12 значений, игнорируя все, кроме последнего.
Предлагаемый (итеративный)
from itertools import islice
from typing import Iterable
def balances(
initial_balance: float,
annual_interest_rate: float,
minimum_monthly_payment_rate: float,
) -> Iterable[float]:
balance = initial_balance
monthly_interest_rate = annual_interest_rate / 12
while True:
minimum_monthly_payment = balance * minimum_monthly_payment_rate
monthly_unpaid_balance = balance - minimum_monthly_payment
balance = monthly_unpaid_balance * (1 + monthly_interest_rate)
yield balance
def main():
for balance in islice(
balances(
initial_balance=484.00,
annual_interest_rate=0.20,
minimum_monthly_payment_rate=0.04,
),
12,
):
pass
print(f'Remaining Balance: {balance:.2f}')
if __name__ == '__main__':
main()
Упрощение внутреннего цикла заменило бы его на
balance *= (1 - minimum_monthly_payment_rate) * (1 + monthly_interest_rate)
что эквивалентно.
Предлагаемый (составной)
Еще лучше полностью избавиться от цикла и просто использовать мощность:
def compound(
initial_balance: float,
annual_interest_rate: float,
minimum_monthly_payment_rate: float,
months: int,
) -> float:
monthly_interest_rate = annual_interest_rate / 12
return initial_balance * (
(1 - minimum_monthly_payment_rate) * (1 + monthly_interest_rate)
) ** months
def main():
balance = compound(
initial_balance=484.00,
annual_interest_rate=0.20,
minimum_monthly_payment_rate=0.04,
months=12,
)
print(f'Remaining Balance: {balance:.2f}')
if __name__ == '__main__':
main()
В balances функция немного длинная. Содержимое цикла может быть другой функцией. Эта функция отвечает за выполнение этого требования:
За каждый месяц рассчитывайте выписки по ежемесячному платежу и остатку
Вместо yield-создание конструкции с month, minimum_monthly_payment, а также balance для каждой итерации цикла вы можете return в конце петли. Фактически, month а также minimum_monthly_payment не используется вообще, поэтому вы можете вернуть только оставшиеся balance в конце 12 месяцев.
Поскольку balances функция теперь возвращает только одно число, вы можете избавиться от сложного кода на main. Просто возьмите этот номер и распечатайте его.
После этих изменений переименуйте balances метод к чему-то более значимому.

Разве не было бы бесполезно давать отрицательный баланс? Может быть, сделай это
while balance >= 0— РэкетирHaskeller
Возможный. Добавьте это, если хотите. Существуют некоторые типы счетов (без кредитных карт), для которых было бы полезно иметь возможность отображать как кредитное, так и дебетовое состояние.
— Райндериен
Тем не менее, сделайте небольшую математику, и вы обнаружите, что баланс никогда не опускается до нуля или ниже нуля за конечное количество итераций.
— Райндериен