Форум сайта python.su
Представляю на Вашу критику функцию записи суммы прописью. Уж очень не нравится код. Кому не лень, подскажите, как его сократить и улучшить.
#!/usr/bin/env python
# -*- coding: cp1251 -*-
“сумма прописью”
import string
def summa_propis(sums, fix='.'):
#создаем словари с вариантами текста
rub_ed = {
‘1’: ‘один рубль’,
‘2’: ‘два рубля’,
‘3’: ‘три рубля’,
‘4’: ‘четыре рубля’,
‘5’: ‘пять рублей’,
‘6’: ‘шесть рублей’,
‘7’: ‘семь рублей’,
‘8’: ‘восемь рублей’,
‘9’: ‘девять рублей’,
‘0’: ‘рублей’
}
rub_des = {
‘1’: ‘десять’,
‘2’: ‘двадцать’,
‘3’: ‘тридцать’,
‘4’: ‘сорок’,
‘5’: ‘пятьдесят’,
‘6’: ‘шестьдесят’,
‘7’: ‘семьдесят’,
‘8’: ‘восемьдесят’,
‘9’: ‘девяносто’,
‘0’: ‘'
}
rub_sot = {
’1': ‘сто’,
‘2’: ‘двести’,
‘3’: ‘триста’,
‘4’: ‘четыреста’,
‘5’: ‘пятьсот’,
‘6’: ‘шестьсот’,
‘7’: ‘семьсот’,
‘8’: ‘восемьсот’,
‘9’: ‘девятьсот’,
‘0’: ‘'
}
rub_tys = {
’1': ‘одна тысяча’,
‘2’: ‘две тысячи’,
‘3’: ‘три тысячи’,
‘4’: ‘четыре тысячи’,
‘5’: ‘пять тысяч’,
‘6’: ‘шесть тысяч’,
‘7’: ‘семь тысяч’,
‘8’: ‘восемь тысяч’,
‘9’: ‘девять тысяч’,
‘0’: ‘тысяч’
}
rub_mil = {
‘1’: ‘один миллион’,
‘2’: ‘два миллиона’,
‘3’: ‘три миллиона’,
‘4’: ‘четыре миллиона’,
‘5’: ‘пять миллионов’,
‘6’: ‘шесть миллионов’,
‘7’: ‘семь миллионов’,
‘8’: ‘восемь миллионов’,
‘9’: ‘девять миллионов’,
‘0’: ‘миллионов’
}
#исключения
rub_isk = {
‘10’: ‘десять’,
‘11’: ‘одиннадцать’,
‘12’: ‘двенадцать’,
‘13’: ‘тринадцать’,
‘14’: ‘четырнадцать’,
‘15’: ‘пятнадцать’,
‘16’: ‘шестнадцать’,
‘17’: ‘семнадцать’,
‘18’: ‘восемнадцать’,
‘19’: ‘девятнадцать’
}
kop_ed = {
‘1’: ‘копейка’,
‘2’: ‘копейки’,
‘3’: ‘копейки’,
‘4’: ‘копейки’
}
tmp = “”
tmp_r = “”
tmp_k = “”
rub = “”
kop = “”
rub_lst =
kop_lst =
lst_ed =
lst_sot =
lst_tys =
lst_mil =
#разделяем рубли и копейки по фиксатору, который можно задать самим
try:
rub, kop = sums.split(fix)
rub_lst = list(rub)
kop_lst = list(kop)
#разбиваем сумму рублей по 3 цифры
if len(rub_lst) > 3:
lst_ed = rub_lst
lst_sot = rub_lst
else:
lst_ed = rub_lst
if len(rub_lst) > 6:
lst_tys = lst_sot
lst_mil = lst_sot
else:
lst_tys = lst_sot
#составляем кусок с миллионами
if lst_mil != :
if len(lst_mil) == 1:
tmp_r = rub_mil.get(lst_mil)
elif len(lst_mil) == 2:
if lst_mil == ‘1’:
tmp_r = rub_isk.get(lst_mil+lst_mil)+' миллионов'
else:
tmp_r = rub_des.get(lst_mil)+rub_mil.get(lst_mil)
elif len(lst_mil) == 3:
if lst_mil == ‘1’:
tmp_r = rub_sot.get(lst_mil)+' '+ \
rub_isk.get(lst_mil+lst_mil)+' миллионов'
elif lst_mil == ‘0’ and lst_mil != ‘0’:
tmp_r = rub_sot.get(lst_mil)+' '+rub_mil.get(lst_mil)
elif lst_mil == ‘0’ and lst_mil == ‘0’:
tmp_r = rub_sot.get(lst_mil)+' миллионов'
else:
tmp_r = rub_sot.get(lst_mil)+' '+ \
rub_des.get(lst_mil)+' '+rub_mil.get(lst_mil)
tmp_r = tmp_r+' '
#составляем кусок с тысячами
if lst_tys != and lst_tys != :
if len(lst_tys) == 1:
tmp_r = tmp_r+rub_tys.get(lst_tys)
elif len(lst_tys) == 2:
if lst_tys == ‘1’:
tmp_r = tmp_r+rub_isk.get(lst_tys+lst_tys)+' тысяч'
else:
tmp_r = tmp_r+rub_des.get(lst_tys)+rub_tys.get(lst_tys)
elif len(lst_tys) == 3:
if lst_tys != ‘0’:
if lst_tys == ‘1’:
tmp_r = tmp_r+rub_sot.get(lst_tys)+' '+ \
rub_isk.get(lst_tys+lst_tys)+' тысяч'
elif lst_tys == ‘0’ and lst_tys != ‘0’:
tmp_r = tmp_r+rub_sot.get(lst_tys)+' '+rub_tys.get(lst_tys)
elif lst_tys == ‘0’ and lst_tys == ‘0’:
tmp_r = tmp_r+rub_sot.get(lst_tys)+' тысяч'
else:
tmp_r = tmp_r+rub_sot.get(lst_tys)+' '+ \
rub_des.get(lst_tys)+' '+rub_tys.get(lst_tys)
else:
if lst_tys == ‘1’:
tmp_r = tmp_r+rub_isk.get(lst_tys+lst_tys)+' тысяч'
elif lst_tys == ‘0’ and lst_tys != ‘0’:
tmp_r = tmp_r+rub_tys.get(lst_tys)
elif lst_tys == ‘0’ and lst_tys == ‘0’:
tmp_r = tmp_r
else:
tmp_r = tmp_r+rub_des.get(lst_tys)+ \
‘ ’+rub_tys.get(lst_tys)
tmp_r = tmp_r+' '
#составляем последний кусок
if lst_ed != and lst_ed != :
if len(lst_ed) == 1:
tmp_r = tmp_r+rub_ed.get(lst_ed)
elif len(lst_ed) == 2:
if lst_ed == ‘1’:
tmp_r = tmp_r+rub_isk.get(lst_ed+lst_ed)+' рублей'
else:
tmp_r = tmp_r+rub_des.get(lst_ed)+rub_ed.get(lst_ed)
elif len(lst_ed) == 3:
if lst_ed != ‘0’:
if lst_ed == ‘1’:
tmp_r = tmp_r+rub_sot.get(lst_ed)+' '+ \
rub_isk.get(lst_ed+lst_ed)+' рублей'
elif lst_ed == ‘0’ and lst_ed != ‘0’:
tmp_r = tmp_r+rub_sot.get(lst_ed)+' '+rub_ed.get(lst_ed)
elif lst_ed == ‘0’ and lst_ed == ‘0’:
tmp_r = tmp_r+rub_sot.get(lst_ed)+' рублей'
else:
tmp_r = tmp_r+rub_sot.get(lst_ed)+' '+ \
rub_des.get(lst_ed)+' '+rub_ed.get(lst_ed)
else:
if lst_ed == ‘1’:
tmp_r = tmp_r+rub_isk.get(lst_ed+lst_ed)+' рублей'
elif lst_ed == ‘0’ and lst_ed != ‘0’:
tmp_r = tmp_r+rub_ed.get(lst_ed)
elif lst_ed == ‘0’ and lst_ed == ‘0’:
tmp_r = tmp_r+' рублей'
else:
tmp_r = tmp_r+rub_des.get(lst_ed)+ \
‘ ’+rub_ed.get(lst_ed)
elif lst_ed == :
tmp_r = tmp_r+'рублей'
#составляем кусок с копейками
if len(kop_lst) == 1:
tmp_k = kop+'0 копеек'
elif len(kop_lst) == 2:
if kop_lst != ‘1’:
tmp_k = kop+' '+kop_ed.get(kop_lst, ‘копеек’)
else:
tmp_k = kop+' копеек'
except ValueError, x:
print ‘Не могу представить сумму прописью!’, x
tmp = tmp_r+' '+tmp_k #объединяем рубли с копейками
tmp_lst = list(tmp)
tmp_lst = str(tmp_lst).upper() #делаем первую букву заглавной
tmp = ‘'.join(tmp_lst)
return tmp
#print summa_propis(’1000001.00')
Офлайн
Офлайн
С ветвлениями худо-бедно можно бороться так
if condition == 2:
result = action1
elif condition == 3:
result = action2
else:
result = action3
одинаково с:
actions = {2: action1, 3: action2}
result = actions.get(condition, action3)
а
if condition == 2:
result = action1
else:
result = action2
аналогично
result = (condition == 2 and action1) or action2
В pytils (особенно в pytils.dt.distance_of_time_in_words) часто используется второй прием, в YDbf - оба.
Но я бы не ставил самоцелью заменять все if'ы.
P.S. pythonwin уже пропиарил новое место ;)
Отредактировано (Июнь 18, 2007 23:16:59)
Офлайн
j2a
Спасибо большое, реальный метод облегчить код.
Офлайн
proDivaПочитай еще “Функциональное программирование на Python” Мертца много интересного для себя откроешь.
j2a
Спасибо большое, реальный метод облегчить код.
Офлайн
baluВ том числе и финт ушами с массивом :)
ЗЫ когда-то эта проблема всплывала в рассылке zoperus покавыряйся в архивах. Там несколько решений найдено было.
Офлайн
j2aВот именно, что худо-бедно.
С ветвлениями худо-бедно можно бороться так
Офлайн
Если следовать Фаулеру, “дурной запах” ветвлений убирается посредством полиморфизма
Офлайн
Посмотрел на твою и написал по новой:
# -*- coding: cp1251 -*-
ei ={1:(“один”, “два”, “три”, “четыре”, “пять”, “шесть”, “семь”, “восемь”, “девять”, “десять”,
“одинадцать”, “двенадцать”, “тринадцать”, “четырнадцать”, “пятнадцать”, “шестнадцать”,
“семнадцать”, “восемнадцать”, “девятнадцать”, “двадцать”),
2:(“”, “двадцать”, “тридцать”, “сорок”, “пятдесят”, “шестдесят”, “семдесят”, “восемдесят”, “девяносто”, “сто”,),
3:(“сто”, “двести”, “триста”, “четыреста”, “пятсот”, “шессот”, “семсот”, “восемсот”, “девятсот”)}
ei1 = {1: (“тысяча”, “тысячи”, “тысяч”),
2: (“миллион”, “миллиона”, “миллионов”),
3: (“миллиард”, “миллиарда”, “миллиардов”),
0: ('', ‘', ’')}
def __propis1000(summ, prop='', len_=3):
if len(`summ`)< len_: len_=len(`summ`)
if len_ == 0: return prop
elif int(`summ`) == 0 : return __propis1000(int(`summ`), prop=prop+' ', len_=len_-1)
elif summ <= 20: return prop + ei
else: return __propis1000(int(`summ`), prop=prop+ei[int(`summ`)-1]+' ', len_=len_-1)
def __get_cathegory(summ):
if summ=='0' or (5<= int(summ)<=9) or (len(summ)> 1 and 10<=int(summ)<=19):return 2
elif 2<=int(summ)<=4 : return 1
else : return 0
def __check_murrain(fun):
if not hasattr(fun, ‘__call__’):
raise TypeError ('The argument should be a callable')
def wrapper(arg, currency='uk'):
if arg == 0: return “ноль”
res = fun(arg)
res = res.replace(“два тысячи”, “две тысячи”)
res = res.replace(“один тысяча”, “одна тысяча”)
if currency == ‘uk’:
if len(`arg`) > 1 and 11<=int(`arg`)<=12: return res
if(`arg`=='1'): res = res+“одна”
elif (`arg`=='2'): res = res+“две”
return res
return wrapper
@__check_murrain
def propis(summ):
summ = `summ`
ln = range(len(summ), -1, -3)
sp, i = '', 0
for x in ln:
if x > 0:
num = summ
sp = __propis1000(int(num))+ ‘ ’+ei1+' ‘+sp
i += 1
return sp
if __name__ == ’__main__':
print propis(20201,)
Поддерживаются 2 валюты. Если надо рубли вызывай propis(20201, ‘ru’)
Офлайн
balu, не удержался и хочу прокомментировать, а точнее покритиковать Ваш код… Думаю, Ваш пример похож на то, как не стоит писать на питоне. По пунктам:
1) Логика программы очень запутана, и гораздо менее понятна, чем в корневом посте.
2) В подтверждение
res = res.replace("один тысяча", "одна тысяча")
if summ[-1]=='0' or (5<= int(summ[-1])<=9) or (len(summ)> 1 and 10<=int(summ[-2:])<=19):return 2
Отредактировано (Июнь 25, 2007 03:32:01)
Офлайн