Last active
October 2, 2018 13:45
-
-
Save Searge/5555df50738e176ae982b9c21cc86691 to your computer and use it in GitHub Desktop.
Калькулятор на Stepik'у
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"#Калькулятор на Stepik'у\n", | |
"\n" | |
], | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Напишите простой калькулятор, который считывает с пользовательского ввода три строки: первое число, второе число и операцию, после чего применяет операцию к введённым числам (\"первое число\" \"операция\" \"второе число\") и выводит результат на экран.\n", | |
"\n", | |
"Поддерживаемые операции: `+, -, /, *, mod, pow, div`, где \n", | |
"\n", | |
"> mod — это взятие остатка от деления, \n", | |
"\n", | |
"> pow — возведение в степень, \n", | |
"\n", | |
"> div — целочисленное деление.\n", | |
"\n", | |
"Если выполняется деление и второе число равно 0, необходимо выводить строку `\"Деление на 0!\"`.\n", | |
"\nОбратите внимание, что на вход программе приходят **вещественные числа**." | |
], | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"first = float(input())\n", | |
"second = float(input())\n", | |
"action = input()\n", | |
"operations = {\"mod\": \"%\", \"div\": \"//\", \"pow\": \"**\"}\n", | |
"try:\n", | |
" print(eval(\"(\" + str(first) + \")\" + operations.get(action, action) + str(second)))\n", | |
"except ZeroDivisionError:\n", | |
" print('Деление на 0!')" | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"5\n", | |
"0\n", | |
"mod\n", | |
"Деление на 0!\n" | |
] | |
} | |
], | |
"execution_count": 1, | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Нашел интересный вопрос Льва Романова: _\"нельзя как-то заставить питон считать операцию инпута?_ например `s = a + c + b`, где «`с`» это операция?\" - да, можно (правда в предыдущих уроках почти ничего из этого не было)\n", | |
"\n", | |
"Всё довольно просто - на вход мы получаем три значения, два числа и знак, и, если их в правильном порядке соединить друг с другом, получится вполне осмысленное выражение.\n", | |
"\n", | |
"Для того, чтобы это выражение прочитать, есть функция `eval()`, принимающая на вход строку и преобразовывающая её в выражение, с которым интерпретатор может работать. Соответственно, нам необходимо все три значения привести к типу `string*` и объединить их в одну строку, что легко сделать при помощи конкатенации строк.\n", | |
"\n", | |
"Если со знаками `+, -, *, /` всё просто, их интерпретатор воспримет как надо и выдаст корректный результат, то как быть с `pow, div, mod`, ведь таких действий питон не знает. Нужно им как-то задать соответствия и в этом помогает словарь. В словаре задаются пары ключ, значение. В моём решении это переменная operations. Получить значение по ключу можно несколькими способами, но, так как я в словаре указал всего три пары, мне был нужен тот, который избавит меня от лишней условной инструкции, указывающей интерпретатору что делать, если ключа нет в словаре. Это метод `.get()`. Он позволяет получить из словаря значение по ключу, так же в нём можно указать значение, которое будет возвращаться в случае отсутствия указанного ключа в словаре. Выглядит это следующим образом `словарь.get(\"ключ\", \"значение, если ключа нет в словаре\")`.\n", | |
"\n", | |
"Осталось лишь обработать ситуацию, когда что-то делится на `0`. Тут можно было бы использовать условную инструкцию, перечислить условия, когда выдавалось бы сообщение `\"Деление на 0!\"`, но это было бы более громоздко и, на мой взгляд, менее читабельно. Потому я использовал `try...except`. Эта конструкция пробует выполнить действие указанное в блоке `try` и, если возникает ошибка, указанная в `except` (в нашем случае это `ZeroDivisionError`, тоесть деление на 0) действие программы не прерывается, а выполняется блок except, в нашем случае это печать сообщения \"Деление на 0!\".\n", | |
"\n* А вообще, чтобы не совершать лишних преобразований, можно было бы все три переменные считать как `input()`, тогда они будут строками, и не преобразовывать из типа `float` обратно в тип `string`, но я об этом поздно подумал" | |
], | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"a, b, op = input(), input(), input()\n", | |
"print (\"Деление на 0!\" if op in (\"/\", \"div\", \"mod\") and float(b) == 0 else eval(\"({0}){1}\".format(a, {'pow':'**', 'div':'//', 'mod':'%'}.get(op, op) + b)))\n", | |
"\n", | |
"# Калькулятор в два рядки :-)\n", | |
"# перевіряє тільки вказану помилку." | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"6\n", | |
"0\n", | |
"/\n", | |
"Деление на 0!\n" | |
] | |
} | |
], | |
"execution_count": 5, | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# з exec але аж в 4 рядки\n", | |
"\n", | |
"try:\n", | |
" exec('print(({0}){2}{1})'.format(input(),input(),input()).replace('mod','%').replace('div','//').replace('pow','**'))\n", | |
"except(Exception):\n", | |
" print('Деление на 0!')" | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"8\n", | |
"4\n", | |
"pow\n", | |
"4096\n" | |
] | |
} | |
], | |
"execution_count": 6, | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Ще один подібний\n", | |
"\n", | |
"import operator\n", | |
"a,b,c = (input() for _ in range(3))\n", | |
"o = {'+' : operator.add, '-' : operator.sub,'*' : operator.mul,'/' : operator.truediv,'mod' : operator.mod,'pow' : operator.pow,'div' : operator.floordiv}\n", | |
"try:\n", | |
" exec(\"print(o[c](float(a),float(b)))\")\n", | |
"except:\n", | |
" print('Деление на 0!')" | |
], | |
"outputs": [], | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# в один рядок з коментарями :-)\n", | |
"exec(\"print(eval('(a) {} b'.format({'div': '//', 'mod': '%', 'pow':'**'}[o] if o in ['div','mod','pow'] else o))) if not(o in ['div','mod','/'] and float(b)==0) else print('Деление на 0!')\", {'a':float(input()),'b':float(input()),'o':input()})\n", | |
"\n", | |
"'''\n", | |
"\n", | |
"'''\n" | |
], | |
"outputs": [], | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true | |
} | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"черт, ну кто-то же сделал 2.0! >E~~ гугл сходу на `complexity score` выдает pip-пакет radon, а тут им же считают? конечно все эти однострочные сверхбыстрые исполнения - та еще фаллометрия, и что-то мне подсказывает, что в боевых условиях за такие колбасы по рукам-то хорошенько настукивают. но и вправду хотелось бы почитать про оптимизации, внутреннюю организацию python, вот это вот все. так-то курс вообще легкий, если б не эти скоры - давно б уже закончил :-)\n", | |
"\n\n", | |
"[вот офф дока] (https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations)\n", | |
"\n", | |
">и в ней в частности для `floor division` и `modulo` сказано: \n", | |
">>\"The numeric arguments are first converted to a common type.\"\n", | |
"\n", | |
">а для `modulo` еще и особенно подчеркнуто как именно все прекрасно работает и с `floating point`.\n", | |
"\n" | |
], | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Найшвидший\n", | |
"\nexec(\"exec(\\\"print(eval('(a) {} b'.format({'div': '//', 'mod': '%', 'pow':'**'}[o] if o in ['div','mod','pow'] else o))) if not(o in ['div','mod','/'] and float(b)==0) else print('Деление на 0!')\\\", {'a':float(input()),'b':float(input()),'o':input()})\")" | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"8\n", | |
"8\n", | |
"*\n", | |
"64.0\n" | |
] | |
} | |
], | |
"execution_count": 7, | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Це цікаве рішення\n", | |
"a =float(input())\n", | |
"b =float(input())\n", | |
"c =str(input())\n", | |
"\n\n", | |
"if (c=='mod' or c=='div' or c=='/') and b == 0:\n", | |
" print('Деление на 0!')\n", | |
" \n", | |
"elif c==('mod'):\n", | |
" print(a%b)\n", | |
" \n", | |
"elif c==('div'):\n", | |
" print(a//b)\n", | |
" \n", | |
"# але як калькулятор не працює :-)\n", | |
"# тільки заявлені в задачі оператори" | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"5\n", | |
"3\n", | |
"+\n" | |
] | |
} | |
], | |
"execution_count": 2, | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Ще одне хороше рішення\n", | |
"\n", | |
"a, b, c = [input() for i in range(3)]\n", | |
"print (\"Деление на 0!\" if c in (\"/\", \"div\", \"mod\") and float(b) == 0 else eval(\"({0}){1}\".format(a, {'pow':'**', 'div':'//', 'mod':'%'}.get(c, c) + b)))" | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"99\n", | |
"88\n", | |
"/\n", | |
"1.125\n" | |
] | |
} | |
], | |
"execution_count": 8, | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [], | |
"outputs": [], | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true | |
} | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"name": "python3", | |
"language": "python", | |
"display_name": "Python 3" | |
}, | |
"language_info": { | |
"name": "python", | |
"version": "3.6.3", | |
"mimetype": "text/x-python", | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"pygments_lexer": "ipython3", | |
"nbconvert_exporter": "python", | |
"file_extension": ".py" | |
}, | |
"kernel_info": { | |
"name": "python3" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment