#!/usr/bin/env python # coding: utf-8 # # Основы программирования в Python # # *Материал подготовил: Виталий Евтушенко, НИУ ВШЭ* # # Code Style, Variable scopes and Namespace, Testing and Debugging basics, Exception handling and Error Rising # ## [Coding style](https://en.wikipedia.org/wiki/Programming_style) (Стандарт оформления кода) # Commercial Photography # Чтобы упростить процессы и жизнь, человечество начало придумывать некие стандарты: стандарты красоты, золотые стандарты, стандарты уровня жизни, стандарты ведения войны, [стандарты обработки чисел с плавающей точкой](https://en.wikipedia.org/wiki/IEEE_754). Можно предоложить, что **прикладное программирование не обошла стороной стандартизация и в нём тоже есть свои стандарты**. Это предположение будет верным. # # Один из стандартов: **стандарт оформления кода**. Также есть стандарты документации, стандарты используемых библиотек. Почти на всё есть свой стандарт, а иногда еще и внутренняя/локальная/корпоративная договоренность (конвенция). # # **Зачем нужен Coding style?** # - В целом, это очень утилитарная идея. # - **Ограничение на количество символов в строке** - максимальная возможная длина одного монитора, чтобы не использовать scroll bar (полосу прокрутки); # - **Осмысленные имена переменных** (Meaningful variables) ‒ чтобы другой человек _(а также разработчик, который уже через несколько дней ‒ другой человек)_ понимал, что делает переменная. **Пример:** переменная `today_temp` вместо A или переменная `number_of_revolution_per_year_in_developing_countries_first_database` вместо переменной с названием B; # - **Пробелы** ‒ максимизации для читаемости кода; # - **Отступы vs Пробелы** - для отсутствия проблем с компиляцией. # - С его помощью человек, впервые увидевший Ваш код, может потратить меньше времени на понимание кода, если он выполнен согласно стандарту ("согласно стандарту" - примерно равно согласно "здравому смыслу") # - Возможно, *coding style documents* не всегда написаны кровью (по аналогии с техникой безопасности и правилами дорожного движения), но написаны ценой человеко-часов, которые не стоит отдавать вновь и стоит экономить. # # **Что почитать?** # - [PEP 8 ‒ Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) (**README**) # - [Chech PEP8 online](http://pep8online.com/) (**Just paste your code here**) # - [Тест: а у вас стильный Python? (tproger)](https://tproger.ru/quiz/python-style-quiz/) # - [Why does Google not follow PEP8 for Python code?](https://www.quora.com/Why-does-Google-not-follow-PEP8-for-Python-code) и [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html) (**пример корпоративной конвенции о коде**). # ## [Variable scopes and Namespace](https://docs.python.org/3/tutorial/classes.html) # Каждый объект в Python'е существует в своём scope (область видимости). Есть несколько областей видимости # Commercial Photography # # **Как это выглядит на практике?** # Commercial Photography # >**Scopes rules** # - Each name exists in a certain scope. # - When entering a function a new local scope is created. # - After exiting a function its local scope (with all the names # in it) is deleted. # - When referencing a name the Python interpreter first # searches the local scope, then the global scope and finally # the built-in scope. The complete picture also includes an Enclosing scope - check Python # resources. # # **Что почитать?** # - [Documentation](https://docs.python.org/3/tutorial/classes.html) (**стоит почитать**) # - [What Are Python Namespaces (And Why Are They Needed?)](https://code.tutsplus.com/tutorials/what-are-python-namespaces-and-why-are-they-needed--cms-28598) (**стоит почитать**) # - [global_&_return, Intermediate Python](https://lancelote.gitbooks.io/intermediate-python/content/book/global_&_return.html) # - [A Beginner's Guide to Python's Namespaces, Scope Resolution, and the LEGB Rule](http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html) (**стоит почитать**) # - [Short Description of the Scoping Rules?](https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules) (**стоит почитать**) # **Пример #1.** На этом примере видно, как **интерпретатор Python'а сначала ищет переменную a в local scope, не находит и обращается к глобальной переменной a**, плюсуя к ней 5. # In[1]: def function1(): return a + 5 a = 5 print(f'function results is {function1()} and a is still {a}') # **Пример #2.** # А здесь мы **явно говорим, что следует использовать переменную a из global scope** # In[2]: def function1(): global a a = a + 5 return a a = 5 print(f'function results is {function1()} and a is {a}') # **Пример #3.** В этом примере происходит то же самое, что и в первом примере, но исходное значение глобальной переменной изменяется, потому что **list** (*список*) ‒ **mutable type** (*изменяемый тип*). # In[3]: def function2(): a.append(5) return a a = [5] print(f'function results is {function2()} and b is {a}') # ## Testing and Debugging basics (Тестирование и отладка) # При написании программы, которая будет выполнять хоть немного важное задание, требуется тестировать свой код. Одним из примеров тестирования может выступать конструкция [assert](http://pythonz.net/references/named/assert/). Она нужна для проверки истинности утверждения. Примером отладки могут выступать встроенные в IDE отладчики или [библиотеки, позволяющие проводить отладку дажев Jupyter'е](https://davidhamann.de/2017/04/22/debugging-jupyter-notebooks/). # ### Testing # In[1]: assert 2 + 2 == 4 print('right statement') # In[2]: assert 2 + 2 == 5, "Уверены ли Вы, что сумма двух и двух равняется пяти?" print('right statement') # In[3]: assert isinstance(4, int) print('right statement') # In[4]: assert isinstance(4, str), "Почему тут ошибка? Потому что сильная типизация." print('right statement') # **По примеру #2 стоит прочитать**: # - [Strong, Weak, Dynamic, and Static Typed Programming Languages Explained](http://www.josephspurrier.com/strong-weak-dynamic-and-static-typed-programming-languages/) # - [Is python strong typed?](https://stackoverflow.com/questions/11328920/is-python-strongly-typed) # - [Static/Dynamic vs Strong/Weak](https://stackoverflow.com/questions/2351190/static-dynamic-vs-strong-weak) # - [static vs dynamic vs strong vs weak vs duck typing](https://www.koffeinfrei.org/2012/03/19/static-vs-dynamic-vs-strong-vs-weak-vs-duck-typing/) # ### [Debugging](https://ru.wikipedia.org/wiki/%D0%9E%D1%82%D0%BB%D0%B0%D0%B4%D0%BA%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%8B) [(en)](https://en.wikipedia.org/wiki/Debugging) # **В очень общих словах**, это процесс очень подробного исполнения программы (контролируемое исполнение каждого действия, каждой операции и итерации) с мониторингом значения всех переменных или всех желаемых переменных и особо тщательном внимании (остановке) в местах, которые того требуют (где выставлен *breakpoint* ‒ точка остановки). **Нужно, чтобы не выставлять print(variable) в каждом месте программы, когда что-то идёт не так, а использовать уже готовый интерфейс для этого**. # # **Что посмотреть и почитать?** # - [Отладка, Intermediate Python](https://lancelote.gitbooks.io/intermediate-python/content/book/debugging.html) # - [Разработка через тестирование](https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%87%D0%B5%D1%80%D0%B5%D0%B7_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) # - [История термина дебаггинг/отладка на wiki en](https://en.wikipedia.org/wiki/Debugging#Origin_of_the_term) # - [Getting Started with PyCharm 6/8: Debugging](https://www.youtube.com/watch?v=QJtWxm12Eo0) **(стоит посмотреть)** # - [debugging-jupyter-notebooks](https://davidhamann.de/2017/04/22/debugging-jupyter-notebooks/) **(стоит не только посмотреть, почитать код но и установить себе библиотеку для отладки и начать ей пользовать)**. # # **ПАСХАЛЬНОЕ ЯЙЦО**: Первые три человека, кто прочитает эту статью и отправит мне на почту скрин с установленной работающей библиотекой и пример отладки, или окно отладки из IDE (например PyCharm) в процессе отладки с объяснением происходящего получит $+0.5$ балла к накопленной или экзамену, на выбор. # ### Также, мы можем совмещать assert с более сложной концепцией ловли ошибок (см. ниже). # In[ ]: try: assert 2 + 2 == 5 except AssertionError: print('Wow, there were unclear statment!') # ## Exception handling and Error rising (Ловля ошибок и вызов ошибок) # Commercial Photography # # **Иногда, человек пишет код, который наиболее вероятно может сломаться наиболее вероятным образом**. В целом, когда пишешь код, нужно заранее понимать, какие ошибки могут возникнуть и как их обойти, не прибегая к экстренным мерам вроде полной перезагрузки работающей программы (hello, windows blue screan). **Одним из способов контролировать ошибки может служить концепция ловли ошибок.** # # В общем виде, ловля ошибок - управляющая конструкция со следующей схемой [1](https://hadoopguru.blogspot.com/2013/09/java-interview-question-part03.html): # Commercial Photography # # **Что почитать?** # - [Встроенные в язык исключения](https://docs.python.org/3.6/library/exceptions.html) # - [sklearn eceptions](http://scikit-learn.org/stable/modules/classes.html#module-sklearn.exceptions), [numpy seterr](https://docs.scipy.org/doc/numpy-1.14.0/reference/ufuncs.html#error-handling) # - [What is the use of exception handling? Quora](https://www.quora.com/What-is-the-use-of-exception-handling) # - [wiki ru](https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9), [Хабр](https://habr.com/post/311214/) # In[8]: for i in range(2): try: int(input('''Введите числое число. Или хотя бы с плавающей точкой. Но вы же можете ввести буквы, я знаю и готов к этому \n''')) print('Wow, nice job. That is a NUMBER!') except ValueError: print('Ha-ha, i was ready!!1!') # Можно ловить совершенно любую ошибку возникшую. Но так делать не стоит, потому что программа перестает быть очевидной и **Errors should never pass silently (The Zen of Python 0:10).** Лучше (хотя бы) перед этим рассмотреть наиболее вероятные. Пример, при работе с интернетом: ошибка соединения, ошибка возвращаемого кода. **Часто в задачах требуются шаблоные исключения, которые достаточно выучить или держать рядом чтобы сделать copy-paste** # In[9]: lst = list(range(5)) lst.append('5') print(f'lst is {lst}') try: print('Сейчас я попробую суммировать элементы в листе') print('Итак, сумма равна...\n') print(sum(lst)) except: print('''Ой, что-то пошло не так. Не знаю, что могло пойти не так.\n\ И Вы не узнаете. Потому что я выставил исключение на любую ошибку.\n\ Как правило, нет достаточно весомых оснований так делать''') # Ошибка, которая возникает в описанном выше примере: # ```python # TypeError: unsupported operand type(s) for +: 'int' and 'str # ``` # Попробуем решить её: # In[11]: lst = list(range(5)) lst.append('5') print(f'lst is {lst}') try: print('Сейчас я попробую суммировать элементы в листе') print('Итак, сумма равна...\n') print(sum(lst)) except TypeError: print('TypeError was catched. Good work!') except: print('''Ой, что-то пошло не так. Не знаю, что могло пойти не так.\n\ И Вы не узнаете. Потому что я выставил исключение на любую ошибку.\n\ Как правило, нет достаточно весомых оснований так делать''') # Очевидно, что **таким образом можно ловить любую ошибку, встроенную в языке, так и придуманную другими людьми в своих пакетах, фреймворках, библиотеках, проектах**. Люди любят придумывать ошибки, а другие люди любят их ловить, иногда это одни и те же люди. # # **Более того, иногда люди любят вызывать ошибки** [How to catch NotImplementedError Exception in Python?](https://www.tutorialspoint.com/How-to-catch-NotImplementedError-Exception-in-Python). Например, если есть готовый интерфейс, но его методы (функции) еще не до конца реализованы. # In[12]: def function_that_finds_life_meaning(): ''' Эта функция находит смысл жизни. Другая постановка задачи: ответ на главный вопрос жизни, вселенной и всего такого. :input something_meaningfull: dict :output: life_meaning ''' # YOUR CODE HERE raise NotImplementedError() # - here the error rise return life_meaning try: function_that_finds_life_meaning() except NotImplementedError: print('Sorry, The New Ultimate Question of Life, the Universe and Everything is not found yet. Time to be.')