Форум сайта python.su
0
Представляю на Вашу критику функцию записи суммы прописью. Уж очень не нравится код. Кому не лень, подскажите, как его сократить и улучшить.
#!/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')
Офлайн
0
Офлайн
1
С ветвлениями худо-бедно можно бороться так
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)
Офлайн
0
j2a
Спасибо большое, реальный метод облегчить код.
Офлайн
0
proDivaПочитай еще “Функциональное программирование на Python” Мертца много интересного для себя откроешь.
j2a
Спасибо большое, реальный метод облегчить код.
Офлайн
1
baluВ том числе и финт ушами с массивом :)
ЗЫ когда-то эта проблема всплывала в рассылке zoperus покавыряйся в архивах. Там несколько решений найдено было.
Офлайн
1
j2aВот именно, что худо-бедно.
С ветвлениями худо-бедно можно бороться так
Офлайн
14
Если следовать Фаулеру, “дурной запах” ветвлений убирается посредством полиморфизма
Офлайн
0
Посмотрел на твою и написал по новой:
# -*- 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’)
Офлайн
0
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)
Офлайн