├── .gitignore ├── Algorithm ├── Lesson_1.md ├── binary │ ├── binary.md │ └── binary.py ├── img │ ├── Screenshot from 2020-11-20 16-33-39.png │ ├── Screenshot from 2020-11-20 16-37-53.png │ ├── Screenshot from 2020-11-20 16-39-16.png │ ├── Screenshot from 2020-11-20 16-39-56.png │ ├── Screenshot from 2020-11-20 16-40-53.png │ ├── Screenshot from 2020-11-20 16-41-55.png │ ├── Screenshot from 2020-11-20 16-42-59.png │ ├── Screenshot from 2020-11-20 16-44-29.png │ ├── Screenshot from 2020-11-20 16-45-05.png │ ├── Screenshot from 2020-11-20 16-46-04.png │ ├── Screenshot from 2020-11-20 16-49-46.png │ ├── Screenshot from 2020-11-20 16-49-54.png │ ├── Screenshot from 2020-11-20 17-19-47.png │ ├── Screenshot from 2020-11-20 17-19-53.png │ ├── Screenshot from 2020-11-20 17-19-59.png │ ├── Screenshot from 2020-11-20 17-20-06.png │ ├── Screenshot from 2020-12-16 01-43-12.png │ ├── Screenshot from 2020-12-17 03-53-02.png │ ├── Screenshot from 2020-12-17 04-05-14.png │ ├── Screenshot from 2020-12-17 04-08-42.png │ ├── Screenshot from 2020-12-17 04-23-28.png │ ├── Screenshot from 2021-01-01 03-39-21.png │ ├── Screenshot from 2021-01-01 03-39-27.png │ ├── Screenshot from 2021-01-01 05-07-53.png │ ├── Screenshot from 2021-01-02 00-22-17.png │ ├── Screenshot from 2021-01-02 00-40-50.png │ ├── Screenshot from 2021-01-02 00-46-28.png │ ├── Screenshot from 2021-01-02 00-53-42.png │ ├── Screenshot from 2021-01-02 01-15-33.png │ ├── Screenshot from 2021-01-02 01-19-40.png │ ├── Screenshot from 2021-01-02 01-37-44.png │ ├── Screenshot from 2021-01-02 02-28-06.png │ ├── Screenshot from 2021-01-02 02-43-11.png │ ├── Screenshot from 2021-01-02 03-21-33.png │ ├── Screenshot from 2021-01-02 03-31-38.png │ ├── Screenshot from 2021-01-02 03-35-25.png │ ├── Screenshot from 2021-01-02 03-47-52.png │ ├── Screenshot from 2021-01-02 05-25-13.png │ ├── Screenshot from 2021-01-02 05-30-50.png │ ├── Screenshot from 2021-01-02 05-44-45.png │ ├── Screenshot from 2021-01-02 05-59-04.png │ ├── Screenshot from 2021-01-02 06-00-26.png │ ├── Screenshot from 2021-01-02 06-02-17.png │ ├── Screenshot from 2021-01-02 06-14-42.png │ ├── Screenshot from 2021-01-02 06-19-47.png │ ├── Screenshot from 2021-01-02 06-22-36.png │ ├── Screenshot from 2021-01-02 06-26-12.png │ ├── Screenshot from 2021-01-02 06-32-26.png │ ├── selection_sort_1.png │ ├── selection_sort_2.png │ └── selection_sort_3.png └── selection │ ├── selection_sort.md │ └── selection_sort.py ├── Example ├── Practice_1 │ ├── 1.py │ ├── 2.py │ ├── 3.py │ ├── 4.py │ ├── 5.py │ ├── 6.py │ ├── 7.py │ ├── CSV │ │ ├── CSV.py │ │ ├── TB │ │ │ └── TB_data_dictionary_2021-07-22.csv │ │ ├── csv-1 │ │ │ ├── exp-1.csv │ │ │ ├── exp-2.csv │ │ │ └── new-exp-1.csv │ │ └── data.csv │ ├── convertor_cover_img.py │ ├── dadata │ │ ├── address.txt │ │ └── get_geo_from_dadata.py │ ├── get_videos.py │ └── tic_tac_toe.py └── Practice_2 │ ├── 1.py │ ├── 2.py │ ├── 3.py │ └── 4.py ├── Leetcode └── example_1.md ├── Other-theory ├── Part_1 │ ├── 12_factor.md │ ├── KISS.md │ └── REST_SOAP.md ├── Part_2 │ └── AMQR.md ├── Part_3 │ └── pattern_1.md ├── Part_4 │ ├── img │ │ ├── 1.png │ │ └── 2.jpg │ └── part_1.md └── Part_5 │ └── part_1.md ├── README.md ├── Theory ├── Part_1 │ ├── Annotations.md │ ├── Base.md │ ├── Garbage_collector.md │ ├── Interactive_mode_REPL.md │ ├── Memory_C_Python.md │ ├── Memory_Pymalloc.md │ ├── Scopes_LEGB.md │ └── Version_difference.md ├── Part_10 │ ├── Questions_1.md │ └── Questions_2.md ├── Part_11 │ └── Flask │ │ └── Lesson_1.md ├── Part_13 │ ├── dt_1.md │ └── dt_2.md ├── Part_14 │ └── geo_1.md ├── Part_15 │ └── alchemy_1.md ├── Part_2 │ ├── Boolean.md │ ├── Data_types.md │ ├── Dict.md │ ├── Integer_float.md │ ├── List.md │ ├── None.md │ ├── String.md │ ├── Tuple.md │ └── set.md ├── Part_3 │ ├── Arithmetic.md │ ├── Assigment.md │ ├── Bitwise.md │ ├── Comparison.md │ ├── Identity.md │ ├── Logical.md │ └── Membership.md ├── Part_4 │ ├── Break.md │ ├── Continue.md │ ├── For.md │ ├── If_else.md │ ├── Ternary_operator.md │ ├── Try.md │ └── While.md ├── Part_5 │ ├── Default_function_arguments.md │ ├── Function_closures.md │ ├── Function_lambda.md │ ├── Functions.md │ └── Packing_and_unpacking_function_arguments.md ├── Part_6 │ ├── Access_modifiers.md │ ├── Descriptors.md │ ├── Dunder_method.md │ ├── Inheritance.md │ ├── Mechanism__slots__.md │ ├── Object_1.md │ ├── Object_2.md │ ├── Object_3.md │ ├── Pattern.md │ └── Privacy.md ├── Part_7 │ ├── Decorator.md │ ├── Exceptions.md │ ├── Function_all_any.md │ ├── Iterators_expression_generators.md │ ├── List_comprehensions.md │ ├── With.md │ └── Yield.md ├── Part_8 │ ├── Copy_object.md │ ├── Ellipsis.md │ ├── File.md │ ├── Function_enumerate.md │ ├── Get_information_about_memory.md │ ├── Hash.md │ ├── Module.md │ ├── Unpacking.md │ ├── Virtual.md │ └── pypi.md └── Part_9 │ ├── Geo_data.md │ ├── Module_Async.md │ ├── Module_CSV.md │ ├── Module_crontab.md │ ├── Module_functools.md │ ├── Module_moviepy.md │ ├── Module_os_1.md │ ├── Module_os_2.md │ ├── Module_pathlib.md │ ├── Module_prettytable.md │ ├── Module_pyperclip.md │ ├── Module_pyshorteners.md │ ├── Module_random.md │ ├── Module_re.md │ ├── Module_requests.md │ ├── Module_socket.md │ ├── Module_sys.md │ ├── Module_time.md │ ├── Module_weakref.md │ ├── Module_webbrowser.md │ ├── Pydentic.md │ ├── argparse.md │ ├── google_drive.md │ ├── jsonschema.md │ └── logger.md ├── links.md └── questions.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | venv 3 | env/ -------------------------------------------------------------------------------- /Algorithm/binary/binary.md: -------------------------------------------------------------------------------- 1 | Бинарный поиск 2 | --- 3 | --- 4 | Алгоритм работает с отсортированным списком элементов, при поиске 5 | искомого элемента, список делится по полам и сравнивается с элементом, 6 | таким образом искомая область делится на двое при каждой итерации. 7 | 8 | Загадона: 57 9 | Список элементов: 100 10 | 11 | [0...100]/2 12 | 50<57 13 | [50...100]/2 14 | 75>57 15 | [50...75]/2 16 | 63>57 17 | [50...63]/2 18 | 57==57 19 | 20 | С бинарным поиском мы каждый раз загадываем число в середине диапазона 21 | и исключаем половину оставшихся чисел. 22 | 23 | 100 -> 50 -> 25 -> 13 -> 7 -> 4 -> 2 -> 1 24 | 1 2 3 4 5 6 7 25 | Максимальное количество шагов = 7 26 | 27 | То есть за 7 шагом мы гарантированно найдем нужное значение их 100 28 | элементов. 29 | 30 | Скорость этого алгоритма поиска полностью показывает себя с большими 31 | числами, сокращая их в два раза на каждом ходе, так для нахождения 32 | нужного элемента из 240 000 потребуется всего 18 шагов. 33 | 34 | Таким образом бинарный поиск выполняется за время равное log по 35 | основанию 2 от числа n, где n - это количество искомых элементов. 36 | 37 | Если 240 000 элементов проверяются по порядку, то потребуется 240 000 38 | проверок, такое время называется линейным временем поиска и время его 39 | выполнения записывается как O(n) где n - количество элементов. 40 | 41 | Время выполнения Бинарного поиска O(log n) то есть время поиска равно 42 | логарифму от числа по основанию 2. 43 | 44 | Время выполнения алгоритмов может расти с разной скоростью. 45 | 46 | Бинарный поиск: 1 миллиард просчитается за 30 шагов, если на каждый 47 | шаг уходит 1 мили секунд, то уйдет 30 мс, в то время как для поиска 48 | из 100 элементов уйдет 7 мс, то есть скорость работы алгоритма 49 | увеличивается в двое при каждой итерации. 50 | -------------------------------------------------------------------------------- /Algorithm/binary/binary.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def binary_search_1(unknown, diapason_floor, diapason_ceil, limit_of_search=None): 5 | """ 6 | :param unknown: the number what we search 7 | :param diapason_floor: floor of slice 8 | :param diapason_ceil: ceil of slice 9 | :param limit_of_search: limit of steps of search 10 | :return: 11 | """ 12 | diapason = list(range(diapason_floor, diapason_ceil+1)) 13 | counter = 0 14 | current_number = round(len(diapason)/2) 15 | 16 | while True: 17 | counter += 1 18 | if unknown == current_number: 19 | print('We found your number, is : ', current_number) 20 | print('Number of steps : ', counter) 21 | break 22 | 23 | diapason_len = round(len(diapason)/2) 24 | current_number = diapason[diapason_len] 25 | 26 | # If the unknown number is less than the current 27 | if unknown > diapason[diapason_len]: 28 | diapason = diapason[diapason_len:] 29 | # If the unknown number is higher than the current 30 | elif unknown < diapason[diapason_len]: 31 | diapason = diapason[:diapason_len] 32 | 33 | if limit_of_search is not None and counter == limit_of_search: 34 | print('Maximum step limit exceeded : {limit}'.format(limit=limit_of_search)) 35 | break 36 | 37 | 38 | binary_search_1(10, 0, 100, 200) 39 | 40 | -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-33-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-33-39.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-37-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-37-53.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-39-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-39-16.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-39-56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-39-56.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-40-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-40-53.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-41-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-41-55.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-42-59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-42-59.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-44-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-44-29.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-45-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-45-05.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-46-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-46-04.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-49-46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-49-46.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 16-49-54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 16-49-54.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 17-19-47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 17-19-47.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 17-19-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 17-19-53.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 17-19-59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 17-19-59.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-11-20 17-20-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-11-20 17-20-06.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-12-16 01-43-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-12-16 01-43-12.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-12-17 03-53-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-12-17 03-53-02.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-12-17 04-05-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-12-17 04-05-14.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-12-17 04-08-42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-12-17 04-08-42.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2020-12-17 04-23-28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2020-12-17 04-23-28.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-01 03-39-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-01 03-39-21.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-01 03-39-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-01 03-39-27.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-01 05-07-53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-01 05-07-53.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 00-22-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 00-22-17.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 00-40-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 00-40-50.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 00-46-28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 00-46-28.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 00-53-42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 00-53-42.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 01-15-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 01-15-33.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 01-19-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 01-19-40.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 01-37-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 01-37-44.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 02-28-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 02-28-06.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 02-43-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 02-43-11.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 03-21-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 03-21-33.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 03-31-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 03-31-38.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 03-35-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 03-35-25.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 03-47-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 03-47-52.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 05-25-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 05-25-13.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 05-30-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 05-30-50.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 05-44-45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 05-44-45.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 05-59-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 05-59-04.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 06-00-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 06-00-26.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 06-02-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 06-02-17.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 06-14-42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 06-14-42.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 06-19-47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 06-19-47.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 06-22-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 06-22-36.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 06-26-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 06-26-12.png -------------------------------------------------------------------------------- /Algorithm/img/Screenshot from 2021-01-02 06-32-26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/Screenshot from 2021-01-02 06-32-26.png -------------------------------------------------------------------------------- /Algorithm/img/selection_sort_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/selection_sort_1.png -------------------------------------------------------------------------------- /Algorithm/img/selection_sort_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/selection_sort_2.png -------------------------------------------------------------------------------- /Algorithm/img/selection_sort_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Algorithm/img/selection_sort_3.png -------------------------------------------------------------------------------- /Algorithm/selection/selection_sort.md: -------------------------------------------------------------------------------- 1 | Сортировка Выбором 2 | --- 3 | --- 4 | Допустим есть массив состоящий из неотсортированных однородных 5 | элементов. 6 | 7 | 156 8 | 141 9 | 25 10 | 94 11 | . 12 | . 13 | . 14 | 61 15 | 111 16 | 17 | Наша задача отсортировать элементы по убыванию, решение, 18 | пройтись по списку и найти самое большое значение, и добавить его в 19 | новый список, после удаляем его из изначального списка сокращая его 20 | на один элемент, далее повторяем процесс. 21 | 22 | ![](../img/selection_sort_1.png) 23 | 24 | ![](../img/selection_sort_2.png) 25 | 26 | ![](../img/selection_sort_3.png) 27 | 28 | Чтобы проверить каждый элемент в списке требуется пройтись по всем 29 | элементам списка, то есть время прохода по всем элементам равно O(n) 30 | 31 | Также мы проходим каждым элементом по всем элементам так образ 32 | получаем время работы O( n * n ) или O большое от n в квадрате. 33 | 34 | Из-за того что при каждой итерации мы удаляем один выбранный 35 | элемент, то после каждой итерации массив сокращается на 1 число, 36 | так что было бы вернее записать этот алгоритм следующим образом. 37 | 38 | n-1, n-2, n-3 . . . 2, 1 39 | 40 | В среднем проверяется список из 1/2 * n элементов. Так что должно 41 | было получиться O( n * 1/2 * n) но в подсчете O большого такие 42 | остатки как 1/2 игнорируются. 43 | 44 | Этот Алгоритм сортировки O(n * n) считается медленным. 45 | -------------------------------------------------------------------------------- /Algorithm/selection/selection_sort.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def selection_sort(array, type_sort='asc'): 5 | """ 6 | Метод реализует сортировку выборкой. 7 | 8 | :param array: должен быть списком для сортировки. 9 | :param type_sort: аргумент что принимает параметры "asc" или "desc" 10 | и в зависимости от этого сортирует по возрастанию или убыванию. 11 | :return: None 12 | """ 13 | print('Array for sorting : ', array) 14 | counter = 0 15 | result_aray = [] 16 | 17 | # Цикл для определения 18 | while True: 19 | # Каждый раз устанавливаем длину списка заново, что бы 20 | # не выйти за границу списка 21 | array_len = len(array) 22 | current, number = array[0], 0 23 | 24 | # Если в начальном списке остался 1 элемент то он автоматически 25 | # является минимальным, добавляем его и выходим из цикла 26 | if array_len == 1: 27 | result_aray.append(array[0]) 28 | break 29 | 30 | # Проходимся по списку и сравниваем наше значение с 31 | # каждым знач в списке, и определяем большее 32 | for j in range(array_len): 33 | counter += 1 34 | if type_sort == 'asc': 35 | if current < array[j]: 36 | number = j 37 | current = array[j] 38 | elif type_sort == 'desc': 39 | if current > array[j]: 40 | number = j 41 | current = array[j] 42 | 43 | 44 | # Добавляем элемента в финальный список и 45 | # удаляем из изначального массива 46 | result_aray.append(current) 47 | del array[number] 48 | 49 | print('Результат :') 50 | print('Количество шагов = ', counter) 51 | print('Финальный массив = ', result_aray) 52 | 53 | 54 | random_array = [random.randint(0, 10) for i in range(1, 11)] 55 | selection_sort(random_array, 'asc') 56 | # selection_sort(random_array, 'desc') 57 | -------------------------------------------------------------------------------- /Example/Practice_1/CSV/CSV.py: -------------------------------------------------------------------------------- 1 | import csv 2 | 3 | 4 | def func_1(): 5 | """ 6 | В директории csv-1 есть файл exp-1.csv 7 | Файл exp-1.csv содержит таблицу вида: 8 | 9 | full_name; salare; kpi 10 | Ivanov Alex; 100000; 5 11 | Smirnov Alex; 120000; 7 12 | Andreev Vadim; 110000; 4 13 | Petrova Ira; 90000; 3 14 | """ 15 | 16 | def reader_to_csv(): 17 | """ 18 | Используя менеджер контекста with 19 | Получаем из файла csv данные и выводим их терминал. 20 | """ 21 | with open("csv-1/exp-1.csv", newline='') as csvfile: 22 | reader = csv.DictReader(csvfile, delimiter=';') 23 | 24 | for row in reader: 25 | print(row['full_name'], ' | ', row['salare'], ' | ', row['kpi']) 26 | 27 | def write_to_csv(): 28 | """ 29 | Используя менеджер контекста with 30 | Записываем данные в csv файл. 31 | """ 32 | with open("csv-1/exp-1-1.csv", 'w', newline='') as csvfile: 33 | writer = csv.writer(csvfile, delimiter=';') 34 | 35 | writer.writerow(["row 1 el 1", "row 1 el 2", "row 1 el 3"]) 36 | writer.writerow(["row 2 el 1", "row 2 el 2", "row 2 el 3"]) 37 | writer.writerow(["row 3 el 1", "row 3 el 2", "row 3 el 3"]) 38 | 39 | # Получаем данные и выводим в консоль 40 | reader_to_csv() 41 | # Создаем новый файл и записываем в него 42 | write_to_csv() 43 | 44 | 45 | def func_2(): 46 | """ 47 | Использование метода csv.reader 48 | Простейший вывод содержимого файла с использованием with 49 | """ 50 | # csv_path = "TB/TB_data_dictionary_2021-07-22.csv" 51 | csv_path = "csv-1/exp-1.csv" 52 | 53 | with open(csv_path, 'r') as file_obj: 54 | reader = csv.reader(file_obj) 55 | for row in reader: 56 | print(" ".join(row)) 57 | 58 | 59 | def func_3(): 60 | """ 61 | Использование метода csv.reader 62 | Для работы используем csv файл по пути TB/TB_data_dictionary_2021-07-22.csv 63 | тот файл содержит данные о людях болеющих туберкулезом. 64 | """ 65 | def csv_reader(file_obj): 66 | """Читаем данные из csv файла.""" 67 | reader = csv.reader(file_obj) 68 | for row in reader: 69 | print(" ".join(row)) 70 | 71 | # csv_path = "TB/TB_data_dictionary_2021-07-22.csv" 72 | csv_path = "csv-1/exp-1.csv" 73 | with open(csv_path, "r") as f_obj: 74 | csv_reader(f_obj) 75 | 76 | 77 | def func_4(): 78 | 79 | def csv_dict_reader(file_obj): 80 | """ 81 | Используя другой метод, csv.DictReader() получим данные из файла. 82 | Каждая строка в файле представляет из себя словарь,де ключами 83 | являются названия столбцов, 84 | """ 85 | reader = csv.DictReader(file_obj, delimiter=',') 86 | for line in reader: 87 | print(line["first_name"]), # Вывод первого элемента новой строки 88 | print(line["last_name"]) # Вывод второго элемента новой строки 89 | 90 | with open("data.csv") as f_obj: 91 | csv_dict_reader(f_obj) 92 | 93 | 94 | def func_5(): 95 | """Пишем CSV файл""" 96 | 97 | def csv_writer(data, path): 98 | """ 99 | Используя метод csv.writer() получим обьект writer и уже 100 | используя его метод writer.writerow() запишим данные в файл. 101 | """ 102 | with open(path, "w", newline='') as csv_file: 103 | writer = csv.writer(csv_file, delimiter=';') 104 | for line in data: 105 | writer.writerow(line) 106 | 107 | # В результате получим список со списками 108 | data = ["first_name,last_name,city".split(","), 109 | "Tyrese,Hirthe,Strackeport".split(","), 110 | "Jules,Dicki,Lake Nickolasville".split(","), 111 | "Dedric,Medhurst,Stiedemannberg".split(",") 112 | ] 113 | 114 | path = "output.csv" 115 | csv_writer(data, path) 116 | 117 | 118 | def func_6(): 119 | """ 120 | Используя метод DictWriter создадим список со словарями, 121 | и запишим его в файл CSV 122 | """ 123 | def csv_dict_writer(path, fieldnames, data): 124 | """ 125 | Записываем в CSV файл данные используя DictWriter 126 | """ 127 | with open(path, "w", newline='') as out_file: 128 | writer = csv.DictWriter(out_file, delimiter=';', fieldnames=fieldnames) 129 | writer.writeheader() 130 | for row in data: 131 | writer.writerow(row) 132 | 133 | # Получим список со словарями 134 | data = ["first_name,last_name,city".split(","), 135 | "Tyrese,Hirthe,Strackeport".split(","), 136 | "Jules,Dicki,Lake Nickolasville".split(","), 137 | "Dedric,Medhurst,Stiedemannberg".split(",") 138 | ] 139 | 140 | # Финальный список что будет содержать все словари 141 | my_list = [] 142 | # Список с первым рядом, в котором названия столбцов 143 | fieldnames = data[0] 144 | # Цикл проходится по всем спискам, создавая из них 145 | # словари и добавляя их к финальному списку 146 | for values in data[1:]: 147 | # print(fieldnames, values) 148 | inner_dict = dict(zip(fieldnames, values)) # Трансформ списка в словарь 149 | # print('inner_dict = ', inner_dict) 150 | my_list.append(inner_dict) # Добавление словаря в финал список 151 | 152 | path = "dict_output.csv" 153 | csv_dict_writer(path, fieldnames, my_list) 154 | 155 | 156 | # Раскоментите чтобы выбрать нужный вариант 157 | # func_1() 158 | # func_2() 159 | # func_3() 160 | # func_4() 161 | # func_5() 162 | # func_6() 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /Example/Practice_1/CSV/csv-1/exp-1.csv: -------------------------------------------------------------------------------- 1 | full_name;salare;kpi 2 | Ivanov Alex;100000;5 3 | Smirnov Alex;120000;7 4 | Andreev Vadim;110000;4 5 | Petrova Ira;90000;3 -------------------------------------------------------------------------------- /Example/Practice_1/CSV/csv-1/exp-2.csv: -------------------------------------------------------------------------------- 1 | Year,Industry_aggregation_NZSIOC,Industry_code_NZSIOC,Industry_name_NZSIOC,Units,Variable_code 2 | 2021,Level 1,99999,All industries,Dollars (millions),H01 3 | 2020,Level 2,99999,All industries,Dollars (millions),H04 4 | 2022,Level 3,99999,All industries,Dollars (millions),H05 5 | 2020,Level 4,99999,All industries,Dollars (millions),H07 6 | 2019,Level 5,99999,All industries,Dollars (millions),H08 7 | 2021,Level 6,99999,All industries,Dollars (millions),H09 8 | 2018,Level 7,99999,All industries,Dollars (millions),H10 9 | 2015,Level 8,99999,All industries,Dollars (millions),H11 10 | 2016,Level 9,99999,All industries,Dollars (millions),H12 11 | 2017,Level 10,99999,All industries,Dollars (millions),H13 12 | 2018,Level 11,99999,All industries,Dollars (millions),H14 13 | 2019,Level 12,99999,All industries,Dollars (millions),H19 14 | 2020,Level 13,99999,All industries,Dollars (millions),H20 15 | -------------------------------------------------------------------------------- /Example/Practice_1/CSV/csv-1/new-exp-1.csv: -------------------------------------------------------------------------------- 1 | row 1 el 1;row 1 el 2;row 1 el 3 2 | row 2 el 1;row 2 el 2;row 2 el 3 3 | row 3 el 1;row 3 el 2;row 3 el 3 4 | -------------------------------------------------------------------------------- /Example/Practice_1/CSV/data.csv: -------------------------------------------------------------------------------- 1 | first_name,last_name,address,city,state,zip_code 2 | Tyrese,Hirthe,1404 Turner Ville,Strackeport,NY,19106-8813 3 | Jules,Dicki,2410 Estella Cape Suite 061,Lake Nickolasville,ME,00621-7435 4 | Dedric,Medhurst,6912 Dayna Shoal,Stiedemannberg,SC,43259-2273 -------------------------------------------------------------------------------- /Example/Practice_1/convertor_cover_img.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | """ 4 | Модуль для стилизации изображений. 5 | 6 | add_alpha_canal - Добавляет изображению прозрачность в указанном 7 | размере, оот 0 до 256 8 | 9 | convert_jpg_to_png - Конвертирует изображение из .jpg в .png 10 | и сохраняет его в том же файле 11 | 12 | create_combine_image - Накладывает изображение с Альфа каналом 13 | на обычное изображение. 14 | 15 | Пример использования: 16 | add_alpha_canal('2.png', 'Filter-1.png', 128) 17 | convert_jpg_to_png('123.jpg', 'Photo-1.png') 18 | create_combine_image('Photo-1.png', 'Filter-1.png', 'Combine-1.png') 19 | """ 20 | 21 | 22 | def convert_jpg_to_png(photo_jpg): 23 | """ 24 | Конвертирует изображение из jpg в png 25 | Возвращаем новый путь к картинке. 26 | """ 27 | img = Image.open(photo_jpg) 28 | photo_png = photo_jpg.replace('.jpg', '.png') 29 | img.save(photo_png) 30 | return photo_png 31 | 32 | 33 | def add_alpha_canal(source_png, alpha_value=128): 34 | """Добавляет png изображению, Альфа канал.""" 35 | img = Image.open(source_png) 36 | img.putalpha(alpha_value) 37 | img.save(source_png) 38 | 39 | 40 | def create_combine_image(photo_png, filter_png, result_img): 41 | """ 42 | Наложение фильтра на изображение. 43 | 44 | Изменяет размер фильтра, подстраивая его под 45 | изображение, накладывает фильтр на изображение. 46 | 47 | photo_png - изображение без прозрачности 48 | filter_png - изображение с прозрачностью 49 | """ 50 | # Открываем изображение 51 | background = Image.open(photo_png) 52 | foreground = Image.open(filter_png) 53 | 54 | # Получаем их размеры 55 | back_width, back_height = background.size 56 | 57 | # Подстраиваем фильтр под изображение 58 | foreground = foreground.resize((back_width, back_height)) 59 | 60 | # Накладываем фильтр на фото и сохраняем 61 | background.paste(foreground, (0, 0), foreground) 62 | background.save(result_img) 63 | -------------------------------------------------------------------------------- /Example/Practice_1/dadata/get_geo_from_dadata.py: -------------------------------------------------------------------------------- 1 | # Установка модуля для работы с API: 2 | # pip3 install dadata 3 | from dadata import Dadata 4 | 5 | 6 | def get_geo_from_dadata(): 7 | api_key = "Тут секретный API ключ" 8 | secret_key = "Тут секретный ключ" 9 | 10 | dadata = Dadata(api_key, secret_key) 11 | 12 | counter, good, error = 0, 0, 0 13 | file_path = 'address.txt' 14 | 15 | with open(file_path, 'r') as file: 16 | 17 | for row in file: 18 | print('-' * 50) 19 | print(f'№ {counter}') 20 | print('address = ', row) 21 | try: 22 | result = dadata.clean(name="address", source="москва сухонская 11") 23 | print('lat = ', result['geo_lat']) 24 | print('lng = ', result['geo_lon']) 25 | good += 1 26 | except Exception as e: 27 | error += 1 28 | print('Не распознан') 29 | 30 | counter += 1 31 | 32 | print('===== Результат =====') 33 | print(f'Всего записей = {counter} \n Распознано = {good} \n Не распознано {error}') 34 | 35 | dadata.close() 36 | 37 | 38 | get_geo_from_dadata() 39 | -------------------------------------------------------------------------------- /Example/Practice_1/get_videos.py: -------------------------------------------------------------------------------- 1 | import os 2 | import youtube_dl 3 | 4 | """ 5 | Данная программа скачивает видео с Youtube и сохраняет в формате mp3 6 | 7 | URL для видео должно быть в формате 'https://www.youtube.com/watch?v=p4KwdJdCy0o' 8 | Обратите внимание что если в URL есть параметр '&list=' ио будет скачан весь 9 | плей лист. 10 | """ 11 | 12 | links = [ 13 | "https://www.youtube.com/watch?v=p4KwdJdCy0o", 14 | ] 15 | 16 | 17 | def uploader(links: list): 18 | 19 | "В цикле скачивает все видео с Youtube" 20 | 21 | ydl_opts = { 22 | # 'outtmpl': "", # Директория для скачивания 23 | 'format': 'bestaudio/best', 24 | 'postprocessors': [{ 25 | 'key': 'FFmpegExtractAudio', 26 | # 'preferredcodec': 'wav', # Формат в котором будет скачено видео 27 | 'preferredcodec': 'mp3', 28 | 'preferredquality': '192' 29 | }], 30 | 'postprocessor_args': [ 31 | '-ar', '16000' 32 | ], 33 | 'prefer_ffmpeg': True, 34 | # 'keepvideo': True # даляет или оставляет оригинал видео 35 | 'keepvideo': False 36 | } 37 | 38 | for video in links: 39 | with youtube_dl.YoutubeDL(ydl_opts) as ydl: 40 | ydl.download([video]) 41 | 42 | 43 | if __name__ == "__main__": 44 | uploader(links) 45 | -------------------------------------------------------------------------------- /Example/Practice_2/1.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def func1(): 4 | class Bank(): 5 | """ 6 | Условие: 7 | Пользователь делает вклад в размере a рублей сроком на years лет 8 | под 10% годовых (каждый год размер его вклада увеличивается на 10%. 9 | Эти деньги прибавляются к сумме вклада, и на них в следующем году тоже 10 | будут проценты). 11 | 12 | Задача: 13 | Написать класс bank, принимающая аргументы a и years, и возвращающую 14 | сумму, которая будет на счету пользователя. 15 | """ 16 | 17 | def __init__(self, summ, years): 18 | self.checkArguments(summ, years) 19 | self.percent = 1.10 20 | self.summ = summ 21 | self.years = years 22 | self.result = self.summ 23 | self.GetResultForYears() 24 | 25 | def ShowResult(self): 26 | print("Сумма {summ} под '{percent}' на {years} лет = {result}".format( 27 | summ=self.summ, 28 | percent=self.percent, 29 | years=self.years, 30 | result=self.result 31 | )) 32 | 33 | def GetResultForYears(self): 34 | for i in range(self.years): 35 | self.result = self.GetResultForYear(self.result, self.percent) 36 | print(self.result) 37 | print(i) 38 | 39 | def GetResultForYear(self, summ, percent): 40 | return summ * percent 41 | 42 | def checkArguments(self, summ, years): 43 | try: 44 | summ = float(summ) 45 | years = int(years) 46 | except: 47 | print("Сумма и год должны быть числами") 48 | raise 49 | 50 | bank = Bank(1000, 3) 51 | bank.ShowResult() 52 | 53 | 54 | def func2(): 55 | """ 56 | Дан список чисел. Превратите его в список квадратов этих чисел. 57 | спользуем для этого 3 способа: циклом, лямбда, и генератор списков 58 | """ 59 | 60 | my_list = [1, 2, 3, 4, 5] 61 | print("Первый способ я списка = ", my_list) 62 | for i in range(len(my_list)): 63 | my_list[i] *= my_list[i] 64 | print(my_list) 65 | 66 | my_list = [2, 3, 4, 5, 6] 67 | print("Второй способ я списка = ", my_list) 68 | sortinf_func = lambda x: x*x 69 | my_list = list(map(sortinf_func, my_list)) 70 | print(my_list) 71 | 72 | my_list = [3, 4, 5, 6, 7] 73 | print("Третий способ я списка = ", my_list) 74 | my_list = [ i*i for i in my_list ] 75 | print(my_list) 76 | 77 | 78 | def func3(): 79 | """ 80 | Число-палиндром с обеих сторон (справа налево и слева направо) читается 81 | одинаково. Самое большое число-палиндром, полученное умножением двух 82 | двузначных чисел – 9009 = 91 × 99. 83 | 84 | Найдите самый большой палиндром, полученный умножением двух трехзначных чисел. 85 | """ 86 | max_a, max_b = 0, 0 87 | 88 | for i in range(100, 1000): 89 | for j in range(100, 1000): 90 | num = str(i * j) 91 | if num == num[::-1]: 92 | max_a = i 93 | max_b = j 94 | result = num 95 | print("{i} * {j} = {num}".format(i=i, j=j, num=num)) 96 | 97 | print("Наибольшее число путем умножения двух трех знач чисел {i} * {j} = {num}". 98 | format(i=max_a, j=max_b, num=result)) 99 | 100 | def check_simple_number(num): 101 | """ 102 | Проверяет является ли целое число простым. 103 | :param num: Целое число 104 | :return: True/False 105 | """ 106 | if type(num) is not int or num <=0: 107 | raise ValueError("Параметр должен быть целым положительным числом.") 108 | else: 109 | if (num==2 or num==3 or num==5) or (num%2!=0) and (num%3!=0) and (num%5!=0) and (num%7!=0): 110 | return True 111 | else: 112 | return False 113 | 114 | 115 | def test_check_simple_number(): 116 | """ 117 | Метод прогоняет числа от 0 до 100 через метод check_simple_number 118 | """ 119 | for num in range(1, 150): 120 | print("Число {num} = {result}" 121 | .format(num=num, result=check_simple_number(num)) 122 | ) 123 | 124 | def is_prime(num): 125 | """ 126 | Еще одна функция для проверки является ли число простым. 127 | :param num: Число 128 | :return: Текст с описанием, является ли число простым 129 | """ 130 | for n in range(2, num): 131 | if num % n == 0: 132 | print("Число {num} не простое".format(num=num)) 133 | break 134 | else: 135 | print("Число {num} простое".format(num=num)) 136 | 137 | 138 | # func1() 139 | # func2() 140 | func3() 141 | -------------------------------------------------------------------------------- /Example/Practice_2/2.py: -------------------------------------------------------------------------------- 1 | 2 | def func1(): 3 | 4 | class Test1(): 5 | """ 6 | Класс будет реагировать на операторы, сравнивать их 7 | по количеству символов. 8 | """ 9 | 10 | def __init__(self, name): 11 | self.name = name 12 | 13 | def __eq__(self, other): 14 | print(f"self = {len(self.name)}", self) 15 | print("other = ", other) 16 | if len(self.name) == other: 17 | return True 18 | return False 19 | 20 | 21 | t1 = Test1('Names') 22 | print(t1==5) 23 | 24 | 25 | def func2(): 26 | class Point(): 27 | """ 28 | Представляет точку на плоскости 29 | """ 30 | def __init__(self, x=0, y=0): 31 | self.x = x 32 | self.y = y 33 | 34 | 35 | pt = Point(1, 2) 36 | print(f"x = {pt.x} y={pt.y}") 37 | 38 | print("Тут мы можем изменить значения переменных из вне") 39 | pt.x = 100 40 | pt.y = 'abc' 41 | print(f"Новые значения x = {pt.x} y={pt.y}") 42 | 43 | 44 | 45 | 46 | def func3(): 47 | class Point2(): 48 | 49 | def __init__(self, x=0, y=0): 50 | self.__x = x 51 | self.__y = y 52 | 53 | def show(self): 54 | print(f"x = {self.__x} y = {self.__y}") 55 | 56 | def setCoords(self, x, y): 57 | self.__x = x 58 | self.__y = y 59 | 60 | def getCoords(self): 61 | return self.__x, self.__y 62 | 63 | 64 | p2 = Point2(10, 20) 65 | p2.show() 66 | 67 | p2.setCoords(100, 200) 68 | p2.show() 69 | 70 | x, y = p2.getCoords() 71 | print(x) 72 | print(y) 73 | 74 | print(p2.getCoords()) 75 | print(type(p2.getCoords())) 76 | 77 | # Это выведет ошибку, ибо поля приватны 78 | # print(p2.__x) 79 | # print(p2.__y) 80 | 81 | 82 | 83 | def func4(): 84 | 85 | class Point3(): 86 | 87 | def __init__(self): 88 | pass 89 | 90 | def getCoords(self): 91 | return self.__x, self.__y 92 | 93 | def setCoords(self, x, y): 94 | if (isinstance(x, int) or isinstance(x, float)) and \ 95 | (isinstance(y, int) or isinstance(y, float)): 96 | self.__x = x 97 | self.__y = y 98 | else: 99 | print("Координаты должны быть числами") 100 | 101 | 102 | pt3 = Point3() 103 | 104 | pt3.setCoords(10, 20) 105 | print(pt3.getCoords()) 106 | 107 | pt3.setCoords("10", 20) 108 | print(pt3.getCoords()) 109 | 110 | 111 | def func5(): 112 | 113 | class Point4(): 114 | static_count = 0 115 | 116 | def __init__(self): 117 | self.dinamic_x = 10 118 | 119 | 120 | def show(x, title=''): 121 | print('='*10, title, '='*10) 122 | print('print = ', x) 123 | print('type = ', type(x)) 124 | 125 | po = Point4() 126 | ps = Point4 127 | 128 | show(po, 'Обьект') 129 | show(ps, 'Статический') 130 | 131 | 132 | def func6(): 133 | """ 134 | Можно использовать класс обращаясь к нему на прямую 135 | """ 136 | 137 | class Point(): 138 | static_name = "Статическое название" 139 | static_number = 10 140 | def __init__(self, name): 141 | self.dinamic_name = name 142 | 143 | print(Point) 144 | print(type(Point)) 145 | 146 | 147 | # Как видим создание любых переменных с ссылками на класс 148 | # ведет к одному и томуже классу 149 | p1 = Point 150 | p2 = Point 151 | 152 | print(p1.static_name) 153 | print(p1.static_number) 154 | p1.static_number = 20 155 | 156 | print(p2.static_name) 157 | print(p2.static_number) 158 | 159 | 160 | def func7(): 161 | class Class5: 162 | print('/*===== Специальные методы классов __getattribute__ =====*/') 163 | 164 | # Метод инициализации __init_() должен возвращать тип Nano тоесть ничего 165 | def __init__(self, i): 166 | self.i = i 167 | 168 | # __getattribute__ Вызывается при обращении к любому атрибуту класса 169 | # По сути своей когда мы обращаемся к любому атрибуту любого класса, срабатывает 170 | # именно этот метод, если мы будем возвращать return self.item То он вызовет себя 171 | # самого, и мы получим ошибку типа: RecursionError: maximum recursion depth exceeded 172 | # Чтобы этого избежать надо исп-ть это: object.__getattribute__(self, item) 173 | def __getattribute__(self, item): 174 | print('Вызван метод __getattribute__()') 175 | return object.__getattribute__(self, item) 176 | 177 | c5 = Class5(30) 178 | print(c5.i) 179 | 180 | 181 | 182 | class Class6: 183 | print('/*===== Специальные методы классов __setattr__ =====*/') 184 | 185 | # Вызывается при внесения значения в атрибут экземпляра класса, 186 | # Если мы присваеваем значение атрибуту этогоже экземпляра класса то 187 | # надо использовать словарь __dict__ иниче метод __setattr__() будет вызван 188 | # повторно и будет зацкливание. 189 | def __setattr__(self, key, value): 190 | print('Вызван метод __setattr__()') 191 | self.__dict__[key] = value # Только так можно присвоить значение атрибуту класса 192 | print(f'Атрибуту {key} присвоено значение {value}') 193 | 194 | c6 = Class6 195 | c6.i = 20 196 | print(c6.i) 197 | 198 | 199 | # func1() 200 | # func2() 201 | # func3() 202 | # func4() 203 | # func5() 204 | # func6() 205 | func7() 206 | -------------------------------------------------------------------------------- /Example/Practice_2/4.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Example/Practice_2/4.py -------------------------------------------------------------------------------- /Leetcode/example_1.md: -------------------------------------------------------------------------------- 1 | 1) Two-sum 2 | 3 | Используя массив целых чисел `nums` и целое число `target`, верните 4 | индексы двух чисел так, чтобы они в сумме составляли `target` 5 | 6 | ```python 7 | class Solution(object): 8 | def twoSum(self, nums, target): 9 | """ 10 | :type nums: List[int] 11 | :type target: int 12 | :rtype: List[int] 13 | """ 14 | for k, v in enumerate(nums): 15 | # Вычитая из target число первого элемента мы оставляем такую часть 16 | # от target что если такого же значения нет в массиве nums то и решения нет 17 | res = target - v 18 | if res in nums[k+1:]: 19 | return [k, nums[k+1:].index(res) + k + 1] 20 | ``` 21 | 22 | --- 23 | 24 | 14) Longest Common Prefix 25 | 26 | Напишите функцию, которая находит самую длинную строку общего префикса среди массива строк. 27 | Если общего префикса нет, вернуть пустую строку "". 28 | 29 | 30 | ```python 31 | class Solution(object): 32 | def longestCommonPrefix(self, strs): 33 | """ 34 | :type strs: List[str] 35 | :rtype: str 36 | """ 37 | pre = '' 38 | for k in range(0, len(min(strs))): 39 | res = {word[k] for word in strs} 40 | if len(res) == 1: 41 | pre += next(iter(res)) 42 | continue 43 | break 44 | return pre 45 | ``` 46 | 47 | --- 48 | 49 | 20) Valid Parentheses 50 | 51 | ```python 52 | class Solution(object): 53 | def isValid(self, s): 54 | """ 55 | :type s: str 56 | :rtype: bool 57 | """ 58 | mix = {"{": "}", "(": ")", "[": "]"} 59 | stack = [] 60 | 61 | # check on valis input 62 | if not (s and 63 | len(s) % 2 == 0 and 64 | s[0] in mix.keys() and 65 | set(s).issubset(set(list(mix.keys()) + list(mix.values())))): 66 | return False 67 | 68 | # we fill the stack with symbols and remove the opposite ones from it 69 | for elem in s: 70 | if elem in mix.keys(): 71 | stack.append(elem) 72 | else: 73 | if len(stack) > 0 and mix[stack[-1]] == elem: 74 | stack.pop() 75 | else: 76 | return False 77 | 78 | # if there is anything left 79 | if len(stack) > 0: 80 | return False 81 | 82 | return True 83 | ``` 84 | 85 | test-case 86 | 87 | ```python 88 | params = { 89 | "(){}}{": False, 90 | "()": True, 91 | "()[]{}": False, 92 | "(]": False, 93 | "{[]}": True, 94 | "": False, 95 | "{": False, 96 | ")": False, 97 | "{([[({([])})]])}": True, 98 | "{([[({([(])})]])}": False, 99 | "{([[({([])})]])}}": False 100 | } 101 | s = Solution() 102 | for case, answer in params.items(): 103 | print(f"Input: {case} Expected: {answer} Output: {s.isValid(case)}") 104 | print('='*40) 105 | ``` 106 | 107 | --- 108 | 109 | 58) Length of Last Word 110 | 111 | Учитывая строку s, состоящую из слов и пробелов, вернуть длину последнего слова в строке. 112 | 113 | ```python 114 | class Solution(object): 115 | def lengthOfLastWord(self, s): 116 | """ 117 | :type s: str 118 | :rtype: int 119 | """ 120 | return len(s.strip().split(' ')[-1]) 121 | ``` 122 | 123 | --- 124 | 125 | 66) Plus One 126 | 127 | Вам дано большое целое число, представленное в виде массива целых чисел `digits`, 128 | где каждое число `digits[i]` является цифрой целого числа. Цифры упорядочены от наиболее 129 | значащего к наименее значащему в порядке слева направо. Большое целое число не содержит 130 | начальных символов равных 0 131 | 132 | ```python 133 | class Solution(object): 134 | def plusOne(self, digits): 135 | """ 136 | :type digits: List[int] 137 | :rtype: List[int] 138 | """ 139 | return list(map(int, str(int(''.join(map(str, digits)))+1))) 140 | ``` 141 | 142 | 143 | -------------------------------------------------------------------------------- /Other-theory/Part_1/12_factor.md: -------------------------------------------------------------------------------- 1 | 12 факторов 2 | --- 3 | 4 | [12 факторов, почитать тут](https://12factor.net/) 5 | 6 | Это набор из 12 рекомендаций о том, как создавать распределенные 7 | веб-приложения, которые можно будет легко развернуть и масштабировать, 8 | этот набор рекомендаций был создан `Heroku` провайдером. 9 | 10 | 1. Базы кода (Codebase) 11 | 2. Зависимости (Dependencies) 12 | 3. Конфигурация (Config) 13 | 4. Вспомогательные сервисы (Backing services) 14 | 5. Сборка, релиз, запуск (Build, release, run) 15 | 6. Процессы (Processes) 16 | 7. Привязка к портам (Port binding) 17 | 8. Параллелизм (Concurrency) 18 | 9. Disposability 19 | 10. Dev/prod паритет (Dev/prod parity) 20 | 11. Логгирование (Logs) 21 | 12. Процессы администратора (Admin processes) 22 | 23 | --- 24 | 3 Конфигурация (Config) 25 | --- 26 | Конфигурация - в данном наборе правил подразумевает использование в качестве 27 | настроек для проекта переменные окружения, это позволяет отделить реализацию 28 | кода от его конфигурации. 29 | -------------------------------------------------------------------------------- /Other-theory/Part_1/REST_SOAP.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Other-theory/Part_1/REST_SOAP.md -------------------------------------------------------------------------------- /Other-theory/Part_2/AMQR.md: -------------------------------------------------------------------------------- 1 | Протокол AMQR 2 | --- 3 | --- 4 | 5 | **Модель OSI** 6 | 7 | 8 | >1) Физический уровень: физическая база OSI (аппаратное обеспечение). 9 | > 10 | > 11 | >2) Канальный уровень: передает данные между нодами. 12 | > 13 | > 14 | >3) Сетевой уровень: направляет трафик (переадресовывает его). 15 | > 16 | > 17 | >4) Транспортный уровень: обеспечивает надежный поток данных, управляет им. 18 | > 19 | > 20 | >5) Сеансовый уровень: отвечает за управление сеансами между приложениями. 21 | > 22 | > 23 | >6) Уровень представления: формирует и представляет данные, которые нужно обработать. 24 | > 25 | > 26 | >7) Прикладной уровень: состоит из набора протоколов, с помощью которых пользователи могут получить доступ к ресурсам (файлам, веб-страницам и т.п.), а также организовать свою совместную работу. На этом уровне и работает AMQP. 27 | > 28 | > Примеры: IRC DNS FTP IMAP SSH 29 | 30 | --- 31 | 32 | **Прикладной уровень (7 уровень)** - это единственный уровень на 33 | котором взаимодействуют пользователи, он определяет, как 34 | происходит связь между процессами или приложениями. 35 | 36 | Протокол обмена данными состоит из правил, регламента того как 37 | требуется оформлять сообщение, чтобы разные приложения 38 | могли одинаково понимать это сообщение, без зависимости 39 | от настроек самого этого приложения и его особенностей. 40 | 41 | --- 42 | 43 | **AMQR (Advanced Message Queuing Protocol)** - это специальный 44 | протокол передачи данных, главная идея которого состоит в том, 45 | что отдельные подсистемы одного приложения, или полностью 46 | независимые приложения, могут обмениваться сообщениями 47 | через AMQR. 48 | 49 | AMQR - это так называемый брокер сообщений, низкая задержка 50 | и высокая производительность, При этом семантика обмена 51 | сообщениями настраивается под нужды конкретного проекта. 52 | 53 | --- 54 | RabbitMQ - одна из конкретных реализаций протокола, так называемый 55 | брокер сообщений 56 | -------------------------------------------------------------------------------- /Other-theory/Part_3/pattern_1.md: -------------------------------------------------------------------------------- 1 | 2 | [comment]: <> (Композиция и агрегация) 3 | 4 | [comment]: <> (---) 5 | 6 | [comment]: <> (SOAP ) 7 | 8 | [comment]: <> (JSON RPC ) 9 | 10 | [comment]: <> (REST API) 11 | 12 | [comment]: <> (Unit тесты) 13 | 14 | [comment]: <> (Django FastAPI) 15 | 16 | Делегирование 17 | --- 18 | 19 | > Выдержка с wikipedia 20 | > 21 | > Делегирование (Delegation) — основной шаблон проектирования, 22 | в котором объект внешне выражает некоторое поведение, но в 23 | реальности передаёт ответственность за выполнение этого 24 | поведения связанному объекту. 25 | 26 | Пример на Python 27 | 28 | ```python 29 | class A: 30 | def f(self): 31 | print('A : вызываем метод f') 32 | 33 | def g(self): 34 | print('A : вызываем метод g') 35 | 36 | class C: 37 | 38 | def __init__(self): 39 | self.A = A() 40 | 41 | def f(self): 42 | return self.A.f() 43 | 44 | def g(self): 45 | return self.A.g() 46 | 47 | c = C() 48 | c.f() #A: вызываем метод f 49 | c.g() #A: вызываем метод g 50 | ``` 51 | 52 | --- 53 | 54 | Композиция 55 | --- 56 | 57 | Композиция - это когда между моделируемыми объектами явно 58 | прослеживается отношение `часть - целое` если мы создаем 59 | машину, то на колесо, двигатель, и окна, создается свой 60 | класс, а на машину свой класс и все подклассы из которых 61 | состоит автомобиль будут атрибутами класса авто, таким образом 62 | есть класс контейнер и классы, что являются его элементами. 63 | 64 | Заключается он в том, что есть класс-контейнер, он же 65 | агрегатор, который включает в себя вызовы других классов. 66 | В результате получается, что при создании объекта 67 | класса-контейнера, также создаются объекты включенных в 68 | него классов. 69 | 70 | Композиция это не наследование, наследование предполагает 71 | принадлежность к какой-то общности (похожесть), а композиция 72 | — формирование целого из частей. Наследуются атрибуты, т. е. 73 | возможности, другого класса, при этом объектов непосредственно 74 | родительского класса не создается. При композиции же 75 | класс-агрегатор создает объекты других классов. 76 | 77 | Скажем требуется подсчитать площадь комнаты которую требуется 78 | заклеить обоями, не включая в расчет потолок, пол, и площадь 79 | тех площадей которые занимают дверь и окна. 80 | 81 | ```python 82 | """ 83 | Класс "комната" – это класс-контейнер для окон и дверей. 84 | Он должен содержать вызовы класса "окно_дверь". 85 | """ 86 | 87 | class WinDoor: 88 | """Для расчета площади двери и окна""" 89 | def __init__(self, x, y): 90 | self.square = x * y 91 | 92 | class Room: 93 | """ 94 | Класс комнаты, для расчета площади комнаты которую 95 | требуется заклеить обоями. 96 | """ 97 | def __init__(self, x, y, z): 98 | """ 99 | Получаем параметры комнаты, и сразу считаем всю площадь, 100 | создаем список в котором будем хранить обьекты площадей которые 101 | треубется исключить из подсчета 102 | """ 103 | self.square = 2 * z * (x + y) 104 | self.wd = [] 105 | 106 | def addWD(self, w, h): 107 | """Создаем обьект с площадью которую треб. исключить""" 108 | self.wd.append(WinDoor(w, h)) 109 | 110 | def workSurface(self): 111 | """Подсчет финальной площади""" 112 | new_square = self.square 113 | for i in self.wd: 114 | new_square -= i.square 115 | return new_square 116 | 117 | r1 = Room(6, 3, 2.7) 118 | print(r1.square) # выведет 48.6 119 | r1.addWD(1, 1) 120 | r1.addWD(1, 1) 121 | r1.addWD(1, 2) 122 | print(r1.workSurface()) # выведет 44.6 123 | ``` 124 | 125 | Класс `WinDoor` создается и используется внутри класса 126 | главного `Room`, это и есть композиция. -------------------------------------------------------------------------------- /Other-theory/Part_4/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Other-theory/Part_4/img/1.png -------------------------------------------------------------------------------- /Other-theory/Part_4/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Other-theory/Part_4/img/2.jpg -------------------------------------------------------------------------------- /Other-theory/Part_4/part_1.md: -------------------------------------------------------------------------------- 1 | Модули `M2Crypto` 2 | --- 3 | --- 4 | 5 | `M2Crypto` - наиболее полная оболочка Python для OpenSSL, 6 | включающая RSA, DSA, DH, HMAC, дайджесты сообщений, симметричные шифры 7 | (включая AES); Функциональность SSL для реализации клиентов и серверов. 8 | 9 | При установки этой библиотеки `pip3 install -r requirements.txt` может возникнуть 10 | следующая проблема: 11 | 12 | ![](img/2.jpg) 13 | 14 | Попробуйте установить библиотеку в саму систему, следующим способом 15 | `sudo apt-get install python-m2crypto` если ошибка все таки возникает 16 | 17 | ![](img/1.png) 18 | 19 | То используйте `sudo apt-get install libssl-dev swig python3-dev gcc` 20 | 21 | После этого можно установить зависимость как обычно 22 | `pip3 install -r requirements.txt` 23 | -------------------------------------------------------------------------------- /Other-theory/Part_5/part_1.md: -------------------------------------------------------------------------------- 1 | Протокол SSH 2 | --- 3 | SSH - Это специальный протокол для управления удаленными серверами на 4 | Linux, работа с удаленным сервером происходит в консоле, и в отличие 5 | от P что позволяет производить работу только с файловой системой, при 6 | работе через SSH мож делать все что угодно как и при обычной работе 7 | в терминале. 8 | 9 | --- 10 | 11 | Для подключения требуется: 12 | 13 | - `ip` адрес сервера 14 | - Порт через который будем подключаться к удаленному серверу, по 15 | дефолту `SSH` использует порт 22, но его можно и переопределить 16 | - Имя и пароль пользователя под которым мы войдем на сервер 17 | 18 | --- 19 | Подключение через SSH В LINUX 20 | --- 21 | Для работы используется утилита `ssh`, есть несколько вариантов 22 | подключения. 23 | 24 | 1) Без указания порта, для этого способа достаточно знать 25 | `имя пользователя`, `ip` и `пароль` 26 | 27 | ``` 28 | ssh <Имя_пользователя>@ 29 | ``` 30 | 31 | 2) С указанием порта если это требуется, стандартным портом является 32 | 22, но его иногда переопределяют для безопасности 33 | 34 | ``` 35 | ssh <Имя_пользователя>@ -p <номер порта> 36 | ``` 37 | 38 | Если все правильно, то после потребуется ввести пароль для пользователя 39 | под которым мы логинемся. 40 | 41 | --- 42 | Модуль `paramiko` для работы с `SSH` из `Python` 43 | --- 44 | Это модуль языка `python` для автоматизации работы с `SSH` протоколом, 45 | с его помощью можно работать с `SSH` и создавать скрипты для выполнения 46 | однотипных действия на удаленном сервере. 47 | 48 | ```python 49 | import paramiko 50 | 51 | host = '192.168.10.10' 52 | user = 'login' 53 | secret = 'password' 54 | port = 22 55 | 56 | # создаем клиент 57 | client = paramiko.SSHClient() 58 | 59 | client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 60 | 61 | # создаем подключение 62 | client.connect(hostname=host, username=user, password=secret, port=port) 63 | 64 | # выполняем команду и получаем результаты 65 | stdin, stdout, stderr = client.exec_command('ls -l') 66 | data = stdout.read() + stderr.read() 67 | 68 | # закрываем соединенин 69 | client.close() 70 | ``` 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Theory/Part_1/Annotations.md: -------------------------------------------------------------------------------- 1 | Аннотации аргументов методов 2 | --- 3 | --- 4 | Мы можем в качестве подсказки указывать какого типа должны быть 5 | аргументы передающиеся в `метод/функцию`, также указывать тип 6 | возвращаемого значения, это не налагает каких либо ограничений, 7 | передавать можно все что угодно, это служит лишь аннотацией для 8 | программиста: 9 | 10 | ```python 11 | def __init__(self, x:int = 0, y:int = 0) -> str: 12 | self.x = x 13 | self.y = y 14 | return "Обьект создан" 15 | ``` 16 | 17 | Указание происходит через двоеточие, указание возвращаемого значения 18 | через стрелку. 19 | 20 | Также в случае если метод имеет аннотации у него появляется специальный 21 | атрибут `__annotations__` 22 | 23 | `__annotations__` - это словарь, который содержит в себе список 24 | аннотаций. 25 | 26 | Пример: 27 | ```python 28 | class Point: 29 | def __init__(self, x:int=0, y:int=0): 30 | self.x = x 31 | self.y = y 32 | 33 | def setCoord(self, x:int=0, y:int=0): 34 | self.x = x 35 | self.y = y 36 | 37 | def getCoord(self) -> tuple: 38 | return self.x, self.y 39 | 40 | 41 | print(issubclass(Point, object)) 42 | 43 | pt = Point(10, 20) 44 | print(pt.setCoord.__annotations__) 45 | print(pt.getCoord.__annotations__) 46 | 47 | # Вывод 48 | # True 49 | # {'x': , 'y': } 50 | # {'return': } 51 | ``` -------------------------------------------------------------------------------- /Theory/Part_1/Base.md: -------------------------------------------------------------------------------- 1 | Тема: История Python 2 | --- 3 | --- 4 | 5 | Python - прообразом для создания являются 2 языка, это `ABC` 6 | и `Modula-3` 7 | 8 | `ABC` - язык без скобок, с отступами, откуда питон и взял свой 9 | визуальный стиль. 10 | 11 | `Modula-3` - был первым языком в котором была конструкция 12 | `try except` так же он был модульным языком, откуда и пошла 13 | модульность самого питона. 14 | 15 | --- 16 | 17 | Интроспекция - динамичность языков программирования 18 | --- 19 | 20 | **introspection** - способность объекта во время выполнения получить 21 | информацию о его внутренней структуре. 22 | 23 | Для интроспекции есть ряд методов которые помогают узнать информацию 24 | об обьекте, такие методы как: `dir()`, `type()`, `isinstance()`, 25 | `hasattr()`, `id()` 26 | 27 | --- 28 | 29 | Байт код 30 | --- 31 | 32 | При интерпретированнии создается Байт код, который никак не привязан 33 | к архитектуре, и может выполняться в разных виртуальных машинах, 34 | по дефолту используется интерпретатор `Cpython`, но есть и другие 35 | вирт машины для его исполнения: PyPy(тот же Cpython только с JIT 36 | компиляцией), Jpython(для Java), 37 | 38 | Существую 2 несовместимых версии питона, 2 и 3 версии, главная 39 | причина это переход строк с байтового на Unicod и многие другие 40 | изменения. 41 | 42 | Модуль - это специальный класс который организует свое содержимое 43 | в некое подобие объекта, Любой файл с `.py` задает модуль.: 44 | 45 | 46 | 47 | 48 | У каждого модуля есть атрибут `__name__` который содержит название 49 | модуля соответствующее названию файла, и не может называться с 50 | цифр, ибо является идентификатором, и импортировать его не 51 | получиться. 52 | 53 | --- 54 | 55 | Все в питоне есть объект какого либо класса: 56 | ```python 57 | a = 54 58 | print(type(a)) 59 | print(type(type(a))) 60 | 61 | # Вывод 62 | # 63 | # 64 | ``` 65 | 66 | --- 67 | 68 | РЕР8 - Это соглашение о программировании в питоне, которое содержит 69 | рекомендации для повышения читаемости кода. -------------------------------------------------------------------------------- /Theory/Part_1/Garbage_collector.md: -------------------------------------------------------------------------------- 1 | Сбор мусора - garbage collection 2 | --- 3 | --- 4 | 5 | Существует 2 способа сборки мусора и питон использует их оба 6 | одновременно. 7 | 8 | 1) `reference counting` - первый способ подсчет ссылок, когда 9 | количество ссылок на объект падает до нуля, этот объект удаляется 10 | из памяти, это удобно и происходит сразу как количество ссылок доходит 11 | до нуля, имеет и недостатки. 12 | 13 | Во-первых, количество ссылок на объект надо где-то хранить что 14 | занимает память. 15 | 16 | Во вторых присвоение или удаление происходит при каждой операции, 17 | то есть занимает время выполнения программы. 18 | 19 | В третьих сборщик мусора ну учитывает циклические ссылки, которые 20 | всегда ссылаются др на др и удалить их не представляется возможным, 21 | ибо количество ссылок никогда не упадет до нуля. 22 | 23 | --- 24 | 25 | Циклические ссылки 26 | --- 27 | 28 | Циклическую ссылку нельзя создать при помощи 2 объектов, требуется 29 | минимум 3, один как точка входа в цикл и 2 других как сам цикл: 30 | 31 | ```python 32 | class Cicle: 33 | 34 | def __init__(self, name): 35 | self.name = name 36 | 37 | def set_link(self, value): 38 | self.value = value 39 | 40 | main = Cicle('main') 41 | left = Cicle('left') 42 | right = Cicle('right') 43 | 44 | main.set_link('left') 45 | left.set_link('right') 46 | right.set_link('left') 47 | 48 | print(main.__dict__) 49 | print(left.__dict__) 50 | print(right.__dict__) 51 | 52 | # Вывод 53 | # {'name': 'main', 'value': 'left'} 54 | # {'name': 'left', 'value': 'right'} 55 | # {'name': 'right', 'value': 'left'} 56 | ``` 57 | 58 | Видим как два объекта `left` и `right` ссылаются друг на друга, это и 59 | есть циклическая ссылка. Мы можем удалить внешние ссылки на сами 60 | объекты, но внутренние ссылки объектов др на др останутся, они не 61 | удаляются, но будут существовать и не будут доступны из вне ибо 62 | ссылки на внешний объект уже пропал. 63 | 64 | --- 65 | 66 | 2) `tracing` - второй способ сбора мусора, суть его заключается в 67 | том что берется объект и из него происходит проход по всем доступным 68 | ссылкам. 69 | 70 | Если находятся объекты, которые не имеют доступ по ссылкам из вне, 71 | то они удаляются, так и отслеживаются циклические ссылки. 72 | 73 | **Еще пример циклических ссылок** 74 | Имеем 2 списка, вносим один список в другой список, и вот получается 75 | кольцевая ссылка, которую можно разрушить только в ручную, сам сборщик 76 | мусора ее не уберет. 77 | 78 | ```python 79 | # Пример циклич-х ссылок 80 | a = [] 81 | b = [] 82 | 83 | a.append(b) 84 | b.append(a) 85 | ``` -------------------------------------------------------------------------------- /Theory/Part_1/Interactive_mode_REPL.md: -------------------------------------------------------------------------------- 1 | Интерактивный режим REPL (read-eval-print loop) 2 | --- 3 | --- 4 | Обычный запуск `python console` для исполнения команд питона, это 5 | специальный режим работы интерпретатора питона в котором введенные 6 | команды сразу же исполняются. 7 | 8 | Такой режим интерпретатора называется REPL (read-eval-print loop): 9 | 10 | 1) `read` - считать команду введенную в консоль 11 | 2) `eval` - в питоне есть одноименная функция для считывания строки 12 | в виде исполняемого кода питона 13 | 3) `print` - вывод результата 14 | 4) `loop` - зацикливание процесса 15 | 16 | По сути этот режим можно имитировать в бесконечном цикле с применением 17 | функций типа: `eval`, `input`, `print`. -------------------------------------------------------------------------------- /Theory/Part_1/Memory_C_Python.md: -------------------------------------------------------------------------------- 1 | Память в Си и память в Python 2 | --- 3 | --- 4 | 5 | Память в Си 6 | --- 7 | Как хранятся переменные в Python ? Представим себе такой язык 8 | программирования как С. В языке С когда мы создаем 2 переменные 9 | каждой из которых присваивается значение 5, то это значение 10 | скопировано в ячейку память и когда мы изменяем значение этой 11 | переменной, то только оно и меняется, для конкретной переменной. 12 | 13 | Каждая переменная хранит 101 в бинарном виде, то есть 4 + 0 + 1 = 5 14 | 15 | ```python 16 | int a = 5 17 | int b = 5 18 | 19 | # variable location value 20 | # a 0x3E8 101 21 | # b 0x3E9 101 22 | ``` 23 | 24 | Меняем значения переменной на `6`, тогда происходит изменение 25 | значения в ячейке памяти, не затрагивая другие переменные. 26 | 27 | ```python 28 | int a = 6 29 | int b = 5 30 | 31 | # variable location value 32 | # a 0x3E8 110 33 | # b 0x3E9 101 34 | ``` 35 | 36 | Таким образом в языке Си есть именно переменные которые хранят 37 | значения и изменение значения конкретной переменной сказывается 38 | именно на ней. 39 | 40 | --- 41 | 42 | Память в Python 43 | --- 44 | В питоне, в отличии, от языка Си нет переменных, есть `имена`, 45 | `ссылки` и `обьекты` объекты хранят в себе сами значения, множество 46 | имен при помощи ссылок указывают на объекты, таким образом мы можем 47 | иметь множество различных имен каждый из которых будет указывать 48 | на один и тот же объект. 49 | 50 | --- 51 | 52 | Подсчет ссылок (reference count) 53 | --- 54 | Подсчет ссылок, питон хранит в себе не только само значение, но и 55 | постоянно подсчитывает количество имен которые ссылаются на это 56 | значение, это и есть подсчет ссылок. 57 | 58 | Что делает питон, для простых объектов таких как строки и числа, 59 | питон создает само значение, а потом для оптимизации работы, не 60 | создает новые значения для переменной, в место этого оставляет 61 | значение не тронутым, а новому имени дает ссылку на этот уже 62 | имеющийся объект. 63 | 64 | ```python 65 | x = 300 66 | y = 300 67 | z = [300, 300] 68 | 69 | print('x : ', id(x)) 70 | print('y : ', id(y)) 71 | 72 | print('z[0] : ', id(z[0])) 73 | print('z[1] : ', id(z[1])) 74 | 75 | print('x == y : ', x == y) 76 | print('x is y : ', x is y) 77 | 78 | # Вывод 79 | 80 | # x : 139707576465360 81 | # y : 139707576465360 82 | 83 | # z[0] : 139707576465360 84 | # z[1] : 139707576465360 85 | 86 | # x == y : True 87 | # x is y : True 88 | ``` 89 | 90 | То есть создав переменную x и дав ей значение `300`, питон создает 91 | значение `300` и направляет ссылку переменной `x` на это значение. 92 | В этот момент счетчик ссылок для значения 300 увеличивается на `+=1` 93 | когда мы создаем еще одну переменную `y` счетчик увеличивается на 94 | `+=1` так образ у нас есть 2 ссылки на одно и то же значение, по 95 | этому функция `id()` которая указывает на уникальное место в памяти 96 | для обеих переменных выдает одинаковый результат, также сравнение 97 | по ссылке при помощи оператора `is` дает True, ибо это один и тот 98 | же объект в памяти. 99 | 100 | Даже когда мы определим список, то есть не простой объект 101 | `z = [300, 300]` его элементы ссылаются на значение `300`, 102 | так что это тоже является ссылками на значение `300` и количество 103 | ссылок уже равняется 4. 104 | 105 | Когда мы присваиваем переменным другие значения, скажем: 106 | 107 | ```python 108 | x = True 109 | y = None 110 | del z 111 | ``` 112 | 113 | То тем самым мы уменьшаем количество ссылок на значение `300` до 114 | нуля, оператор `del` удаляет не значение `300`, а удаляет имя 115 | переменной `z` как ссылку на значение `300`, таким образом и 116 | уменьшаем количество ссылок на значение `300`. 117 | 118 | В питоне каждый объект содержит в себе 3 элемента: 119 | 120 | type: int | Тип хранящегося значения 121 | ref-counter: 4 | Количество ссылок 122 | value: 300 | Само значение -------------------------------------------------------------------------------- /Theory/Part_1/Memory_Pymalloc.md: -------------------------------------------------------------------------------- 1 | Внутреннее устройство памяти Python. Механизм `pymalloc` 2 | --- 3 | --- 4 | 5 | Главная проблема в питоне это потребление памяти, есть такой механизм 6 | как `pymalloc`, введенный в питон с версии 2.3 суть его в том что 7 | когда ОС выделяет память для работы программы, питон использует эту 8 | память, но после этого не возвращает ее обратно в ОС, а оставляет за 9 | собой этот кусок память как выделенный на работу программы, таким 10 | образом мы сталкиваемся с проблемой, если в ходе работы программа 11 | требует резкий скачок в используемой памяти, а после этого пика 12 | памяти требуется уже меньше, то питон все равно оставляет эту память 13 | для себя, что ускоряет работу самой программы на питоне, но замедляет 14 | работу самой ОС. 15 | 16 | Распределитель памяти Python, называемый `pymalloc` - суть его работы 17 | следующая, `pymalloc` выделяет память не по кусочку на текущие 18 | требования, а большим куском в `256 кб` и этот кусок памяти называется 19 | Ареной, далее каждая такая Арена делится на кусочки по `4 кб`, эти 20 | кусочки по `4 кб` называются `pool`(пулами). 21 | 22 | Далее каждый pool делится на блоки различной длинны, их длины могут 23 | быть различны, каждый такой блок выделяется под хранение конкретного 24 | обьекта. 25 | 26 | Есть специальный связанный список `usedpools` который хранит в себе 27 | все пулы с блоками различных размеров, когда мы создаем обьект 28 | то происходит поиск в блоках этих пулов, и если есть блок нужного 29 | размера то обьект помещается в него. 30 | 31 | Если нужного пула разбитого на нужные блоки не находится в списке 32 | `usedpools` то требуется найти свободный пул, то происходит поиск 33 | в свободных пулах, что хранятся в списке `freepools` если он есть, 34 | то берем его из списка свободных пулов, если его нет то берется 35 | Арена, и из нее выделяется кусочек для нового свободного пула, 36 | если в Арене нет места то выделяется новая Арена. 37 | 38 | Когда на обьект удаляется последняя ссылка, то обьект удаляется 39 | при помощи сборщика мусора, когда обьект удален его блок освобождается 40 | и помещается в пулл. 41 | -------------------------------------------------------------------------------- /Theory/Part_1/Scopes_LEGB.md: -------------------------------------------------------------------------------- 1 | Области видимости LEGB 2 | --- 3 | --- 4 | 5 | Аббревиатура - LEGB 6 | --- 7 | **L - local** 8 | 9 | **E - enclosing** 10 | 11 | **G - global** 12 | 13 | **B - built in** 14 | 15 | 4 области видимости в которых ведется поиск переменной, это в локальной 16 | области, далее в области видимости функции более высокого уровня если 17 | она есть, далее в глобальной области, и в конце во встроенной области 18 | `builtin` 19 | 20 | Эти встроенные имена находятся в `builtin` области видимости которая 21 | представляет, из себя файл `builtins.py` это файл где они обьявлены 22 | и импортированы по дефолту в программы. 23 | 24 | --- 25 | 26 | Области видимости 27 | --- 28 | В зависимости от трактовки встречается 2 типа категоризации областей 29 | видимости, либо 3, либо 4 области видимости, где дополнительной еще 30 | одной областью видимости является область `Built-in` которую по сути 31 | можно причислить к глобальной области видимости. 32 | 33 | 1) local - Локальная обл видимости, определяется прямиком внутри 34 | своего блока: 35 | 36 | ```python 37 | var = "Глоб переменная" 38 | 39 | def func(): 40 | var = "Локальная переменная" 41 | print(var) 42 | 43 | print(var) 44 | func() 45 | 46 | # Вывод 47 | # Глоб переменная 48 | # Локальная переменная 49 | ``` 50 | 51 | Есть 2 переменных, с одним именем, одна локальная другая глобальная. 52 | 53 | 2) `global` - Глобальная область определяется на верхнем уровне модуля, 54 | и от туда может быть доступна в локальной области при помощи 55 | спец слова `global` после чего значение глобальной переменной 56 | можно изменять внутри локальной области видимости: 57 | 58 | Это любая обычная переменная определенная на глобальной уровне, 59 | то есть переменная на самом верхнем уровне видимости модуля. 60 | 61 | 62 | 3) `nonlocal` (Enclosing) - Не локальная обл видимости, позволяет 63 | выводить из лок области видимости в более верхний уровень, но 64 | не глобальный уровень, к примеру есть функция в которой определена 65 | еще одна функция, ключ слово `nonlocal` позволяет внутренней 66 | функции выйти на уровень видимости более высокой функции, 67 | но она еще не является глобальной: 68 | 69 | ```python 70 | def func1(): 71 | name = "Первый уровень" 72 | print(name) 73 | 74 | def func2(): 75 | nonlocal name 76 | name = "Второй уровень" 77 | 78 | func2() 79 | print(name) 80 | 81 | func1() 82 | 83 | # Вывод 84 | # Первый уровень 85 | # Второй уровень 86 | ``` 87 | 88 | Если внутри функции через `global` обьявлена переменная, но она не 89 | перезаписывается, то ее значение остается таким же, каким было 90 | изначально. 91 | 92 | ```python 93 | var = "Global" 94 | 95 | def def_1(): 96 | global var 97 | print(var) 98 | 99 | print(var) 100 | def_1() 101 | print(var) 102 | 103 | # Вывод 104 | # Global 105 | # Global 106 | # Global 107 | ``` 108 | 109 | 4) `builtin` - Встроенная обл видимости которая позволяет использовать 110 | стандартный набор классов, эту область еще можно прировнять к 111 | глобальной обл. Сюда входят такие вещи как функция `open()` 112 | которые уже встроены в питон, и которые можно использовать 113 | сразу по дефолту. 114 | 115 | --- 116 | 117 | Функции для работы с обл.видимости `globals()`, `locals()`, `vars()` 118 | --- 119 | --- 120 | 121 | `globals()` - возвращает словарь `dict` глобальных переменных 122 | и их значений, текущей области. 123 | 124 | Таким образом можно получить словарь со всеми переменными в 125 | глобальной области видимости. 126 | 127 | ```python 128 | var = 34 129 | print(globals()) 130 | 131 | # Вывод 132 | # {'__name__': '__main__', 133 | # '__doc__': None, 134 | # '__package__': None, 135 | # . 136 | # . 137 | # . 138 | # 'var':34 139 | # } 140 | ``` 141 | 142 | `locals()` - Функция выводит словарь со всеми локальными переменными, 143 | что определены в текущей обл видимости. 144 | 145 | ```python 146 | def func7(): 147 | one = 1 148 | two = 'два' 149 | print(locals()) 150 | 151 | func7() 152 | 153 | # Вывод 154 | # {'two': 'два', 'one': 1} 155 | ``` 156 | 157 | `vars(obj)` - Функция обращается к методу `__dict__` объекта `obj` 158 | что передан в нее как аргумент. 159 | 160 | Аргумент является не обязательным, если его не передавать то функция 161 | будет работать как `locals()` или `globals()` в зависимости от того 162 | где она вызывается, то есть если аргумент не указан то аргументом по 163 | умолчанию становится объект текущей обл видимости. 164 | -------------------------------------------------------------------------------- /Theory/Part_1/Version_difference.md: -------------------------------------------------------------------------------- 1 | Тема: Разница 2 и 3 версии Python 2 | --- 3 | --- 4 | 5 | Строки и Юникод 6 | --- 7 | Существует Юникод кодировка, с 2 типами кодирования: 8 | 9 | 1) UTF-8 UTF-16 UTF-32 10 | 3) UCS-2 UCS-4 11 | 12 | UTF-16 UTF-32 - число указывает количество затрачиваемых битов. 13 | 14 | Первоначально при переходе с питона 2 на питон 3 использовалась 15 | UTF-16 по этому даже когда мы работаем с символами, что могут 16 | умещаться в ASCII то всеравно тратили больше памяти на их хранение, 17 | по этому с питон 3.3 все определяется в зависимости от строки. 18 | 19 | Если строка умещается в UTF-8, то он и используется, как в случае со 20 | строкой `hello world`, если русские символы то уже используется UTF-16 21 | 22 | Рассмотрим пример, функция `chr()` принимает число и по нему вычисляет 23 | по Юникоду какому символу он соответствует, и наоборот функция ord 24 | принимает символ и вычисляет его число по Юникоду. 25 | 26 | ```python 27 | a = 'hello world' 28 | print(list(map(ord, a))) 29 | 30 | b = 'Привет мир' 31 | print(list(map(ord, b))) 32 | 33 | c = '⏸' 34 | print(list(map(ord, c))) 35 | 36 | print(chr(9208)) 37 | print(chr(127025)) 38 | 39 | # Вывод 40 | # [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100] 41 | # [1055, 1088, 1080, 1074, 1077, 1090, 32, 1084, 1080, 1088] 42 | # [9208] 43 | # ⏸ 44 | # 🀱 45 | ``` 46 | 47 | Как можем видеть строка `hello world` состоит только из латиницы, так 48 | что полностью умещается в ASCII в этой таблице символов содержится 49 | кодировка 127 символов, так и есть с английского слово полностью 50 | умещается в это число, так что для кодировки этой строки 51 | используется UTF-8 52 | 53 | Вторая строка это русские символы, для них уже используется UTF-16 54 | 55 | Третий случай это эмодзи, они тоже есть в таблице Юникода. 56 | 57 | Четвертый случай это символ домино, для него уже используется UTF-32 58 | 59 | 60 | Unicod строки и Байтовые строки в Python 61 | --- 62 | В Питоне есть 2 типа строк, Unicod строки и Байт строки, по дефолту 63 | все строки имеют кодировку Unicod. Для обьявления Байт строк перед 64 | строкой записываем спец символ `b` и она участвует в выводе на 65 | экран, также они имеют разный тип объектов, `str` и `bytes` вот 66 | пример: 67 | 68 | ```python 69 | str_1 = 'привет мир' 70 | str_2 = b'hello world' 71 | 72 | print('Unicod строка: ', str_1) 73 | print('Байтов строка: ', str_2) 74 | 75 | print(f'Тип Unicod роки: {type(str_1)}\nТип Байт строк: {type(str_2)}') 76 | 77 | # Вывод 78 | # Unicod строка: привет мир 79 | # Байтов строка: b'hello world' 80 | # Тип Unicod роки: 81 | # Тип Байт строк: 82 | ``` 83 | 84 | Существует кодировка ASCII - которая включает в себя небольшой 85 | набор чисел и латиницы, именно по этой кодировке работал питон2 86 | 87 | Есть таблица Unicod и ее часть UTF-8 включает в себя всю ASCII и 88 | расширяет ее, теперь в Питон3 по дефолту используется именно эта 89 | кодировка, и это работает не только на содержимое строк, но и на 90 | написание самой программы, теперь в качестве символов имен можно 91 | использовать все то что входит в Unicod, так что теперь можно 92 | давать русские и не только, названия именам: 93 | 94 | ```python 95 | переменна = "Да это работает" 96 | print(переменна) 97 | 98 | class МойКласс: 99 | def __init__(self, x, y): 100 | self.x = x 101 | self.y = y 102 | 103 | обьект_моего_классса = МойКласс(10, 20) 104 | print(обьект_моего_классса.__dict__) 105 | 106 | # Вывод 107 | # Да это работает 108 | # {'x': 10, 'y': 20} 109 | ``` 110 | --- 111 | 112 | Модуль `__future__` 113 | --- 114 | Для того чтобы иметь возможность использовать функции Python3 115 | во второй версии языка, используется спец модуль `__future__` 116 | 117 | ```python 118 | from __future__ import print_function 119 | ``` 120 | 121 | --- 122 | 123 | Функции `chr` и `ord` 124 | --- 125 | 126 | В системе кодировок есть привязка к целым числам, для получения 127 | значения символа от числа или числа от символа, используется 2 128 | метода, все это делается из таблицы имен Unicod. 129 | 130 | 1) `chr()` - по числу возвращает его символ. 131 | 132 | 2) `ord()` - по символу возвращает его число. 133 | 134 | ```python 135 | print(chr(65)) 136 | print(ord('A')) 137 | 138 | # Вывод 139 | # A 140 | # 65 141 | ``` -------------------------------------------------------------------------------- /Theory/Part_11/Flask/Lesson_1.md: -------------------------------------------------------------------------------- 1 | Модуль Flask 2 | --- 3 | --- 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Theory/Part_13/dt_1.md: -------------------------------------------------------------------------------- 1 | Модуль `datetime` самого `python` 2 | --- 3 | --- 4 | 5 | --- 6 | Модуль `timedelta`. Складываем и отнимаем дату/время 7 | --- 8 | 9 | Подмодуль `timedelta` модуля `datetime` можно использовать для сложения 10 | и вычитания даты и времени. 11 | 12 | ```python 13 | import datetime 14 | 15 | # создаем дату/время 16 | my_date = datetime.date(2021, 10, 10) 17 | 18 | # отнимаем от нее один день 19 | my_date = my_date + datetime.timedelta(days=1) 20 | ``` 21 | 22 | 23 | --- 24 | Временные зоны `UTC` и `DTC` 25 | --- 26 | 27 | 28 | --- 29 | Задать временную зону 30 | --- 31 | 32 | Задаем временную зону для даты/времени 33 | 34 | ```python 35 | import datetime 36 | import pytz 37 | 38 | TIME_ZONE = 'Europe/Moscow' 39 | 40 | # создаем временную зону 41 | time_zone = pytz.timezone(TIME_ZONE) 42 | 43 | # переводим дату/время в заданную временную зону 44 | dt = datetime.datetime(2021, 1, 10, 10, 0, 0, tzinfo=time_zone) 45 | ``` 46 | 47 | --- 48 | Скомбинировать дата + время = дата/время 49 | --- 50 | 51 | Создать обьект дата/время из разрозненных частей даты и времени можно 52 | с помощью стандартного метода `combine` модуля `datetime` 53 | 54 | ```python 55 | import datetime 56 | 57 | # создаем дату и время по отдельности 58 | my_date = datetime.date(2021, 10, 10) 59 | my_time = datetime.time(10, 10, 10) 60 | 61 | # создаем дату/время из разрозненных частей 62 | datetime.datetime.combine(my_date, my_time) 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /Theory/Part_13/dt_2.md: -------------------------------------------------------------------------------- 1 | Библиотека `arrow` 2 | --- 3 | --- 4 | 5 | [Репозиторий библиотеки `arrow`](https://github.com/arrow-py/arrow) 6 | 7 | Это удобная библиотека для работы с датой/временем. 8 | 9 | Установка: 10 | 11 | pip install arrow 12 | 13 | Создать дату/время можно стандартным методом `arrow.get()` можно создавать 14 | дату/время как из строки, так и из обьекта дата/время стандартной библиотеки 15 | `python` 16 | 17 | Создав дату/время можем удобно привести ее к временной зоне методом `to()` 18 | 19 | Получить дату, время, дату/время обьекта `arrow` можно с помощью специальных 20 | методов `time()`, `date()`, `datetime()` 21 | 22 | Создаем дату/время и приводим ее к временным зонам, и получаем их `время`, 23 | `дату` и `дату/время` 24 | ```python 25 | import arrow 26 | import datetime 27 | 28 | # временные зоны 29 | TIME_ZONE_1 = 'Europe/Moscow' 30 | TIME_ZONE_2 = 'Asia/Kolkata' 31 | 32 | # создание обьектов даты/время 33 | dt_1 = arrow.get('2013-05-11T21:23:58.970460+07:00') 34 | 35 | dt_2 = arrow.get( 36 | datetime.datetime(2021, 10, 10, 7, 7, 7) 37 | ) 38 | 39 | # задаем временную зону для обьектов даты/время 40 | dt_1.to(TIME_ZONE_1) 41 | dt_2.to(TIME_ZONE_2) 42 | 43 | dt_1.time() 44 | dt_1.date() 45 | dt_1.datetime() 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /Theory/Part_14/geo_1.md: -------------------------------------------------------------------------------- 1 | `OSM geocoder` поиск в установленном радиусе полигона 2 | --- 3 | 4 | В `GIS` для указания площади поиска в полигоне задается 2 точками, 5 | левой нижней точкой и правой верхней, так 4 координаты задают 2 6 | точки по которым и выстраивается полигон в площади которого и 7 | будет вестись поиск. 8 | 9 | При поиске координат по адресу с помощью `OSM` можно устанавливать 10 | радиус поиска координат, к примеру радиус поиска в городе Воронеж 11 | будет задан следующими координатами. 12 | 13 | ```python 14 | # Радиусе в рамках которого будет вестись поиск координат для сообщений 112 15 | GEO_RADIUS_FOR_SEARCH = { 16 | 'Воронеж': ['39.0130423503482', '51.483114965548', '39.65899999999999', '51.902863'] 17 | } 18 | ``` 19 | 20 | `OSM` для поиска используем точку входа в `API` 21 | 22 | ```python 23 | OSM_BASE_URL = "https://nominatim.openstreetmap.org/search.php" 24 | ``` 25 | 26 | Напишем функцию, которая будет искать адрес в указанном полигоне города Воронеж. 27 | 28 | Параметры `get` запроса к точке `API` : 29 | 30 | - `viewbox` это и есть наш полигон для поиска в его площади 31 | - `q` адрес для которого ищем гео-координаты 32 | - `format=jsonv2` формат в которых возвращаемых значений, `python` удобно работать с 33 | `json` ибо он легко конвертируется в словари 34 | - `bounded=1` по дефолту даже если вы указываете радиус поиска `viewbox` работать 35 | он не будет, требуется указать `bounded=1` чтобы радиус координат начался именно в 36 | указанном полигоне 37 | - `limit=1` по дефолту `OSM` возвращает все найденные адреса, этот параметр указывает 38 | до скольки совпадений следует возвращать 39 | 40 | ```python 41 | def osm_geocoder(address: str, search_radius: list = []) -> dict: 42 | """С помощью гео-кодера OSM получает координаты по адресу""" 43 | 44 | # формируем параметры для запрсоа на точку API 45 | source = '{url}?viewbox={search_radius}&q={address}&format=jsonv2&bounded=1&limit=1'.format( 46 | url=settings.OSM_BASE_URL, 47 | search_radius=','.join(search_radius), 48 | address=address 49 | ) 50 | 51 | # делаем запрос стандартной бибилиотекой 52 | geo = requests.get(source) 53 | 54 | # конвертируем в словарь первый эллемент там и находятся координаты 55 | geo = dict(geo.json()[0]) 56 | 57 | # возвращаем координаты 58 | return geo["lon"], geo["lat"] 59 | 60 | 61 | lon, lat = osm_geocoder( 62 | 'Воронеж Перхоровича дом 59', 63 | settings.GEO_RADIUS_FOR_SEARCH['Воронеж'] 64 | ) 65 | ``` 66 | 67 | Помните: 68 | - `OSM` бесплатна и по тому плохо парсит адреса, нормализуйте ваши адреса перед отправкой 69 | - `OSM` работает довольно медленно, по сравнению с `Yandex Geocoder` 70 | (1000 бесплатных запросов в день) но зато бесплатно и без ограничений 71 | 72 | 73 | -------------------------------------------------------------------------------- /Theory/Part_15/alchemy_1.md: -------------------------------------------------------------------------------- 1 | SQLAclhemy 2 | --- 3 | Это фреймворк для работы с реляционными базами данных в Python, 4 | SQLAclhemy по сути это ORM для взаимодействия с БД. У Django есть свой 5 | собственный ORM который поставляется вместе с Django из коробки. 6 | 7 | 8 | --- 9 | Получение данных 10 | --- 11 | 12 | Выполнив запрос данные можно получить в виде кортежа, обратившись к 13 | свойству `_data`, или в виде словаря с помощью специального метода 14 | `_asdict()` который вернет полученную запись данных из сделанного запроса. 15 | 16 | ```python 17 | for row in session.query(User).all(): 18 | row._asdict() 19 | ``` 20 | 21 | --- 22 | Примеры запросов SQLalchemy 23 | --- 24 | 25 | Задача: есть 3 таблицы, требуется сгруппировать данные и одним запросом получить, 26 | email, ресурс принадлежащий ему, и в одну строку перечисление всех объектов 27 | этого ресурса. 28 | 29 | Запрос в SQLalchemy 30 | 31 | ```python 32 | from sqlalchemy import func, delete, distinct, update 33 | 34 | data = session.query( 35 | Subscribe.resource_id.label('resource'), 36 | Email.email.label('email'), 37 | func.array_agg(Subscribe.feature_id).label('features'))\ 38 | .filter( 39 | SubscribeEmail.notification_email_id == Email.id)\ 40 | .filter( 41 | SubscribeEmail.notification_subscribe_id == Subscribe.id).\ 42 | group_by( 43 | Subscribe.resource_id, Email.email).\ 44 | all() 45 | ``` 46 | 47 | Эквивалент sql запроса: 48 | 49 | ```sql 50 | SELECT 51 | ne.email AS email, 52 | ns.resource_id AS resource, 53 | array_agg(ns.feature_id) 54 | FROM public.subscribe_email AS nse 55 | INNER JOIN public.email AS ne ON nse.email_id = ne.id 56 | INNER JOIN public.subscribe AS ns ON nse.subscribe_id = ns.id 57 | GROUP BY 58 | email, 59 | resource 60 | ; 61 | ``` 62 | -------------------------------------------------------------------------------- /Theory/Part_2/Boolean.md: -------------------------------------------------------------------------------- 1 | Тип данных `Boolean` 2 | --- 3 | --- 4 | `Boolean` - класс, что наследуется от типа `int` 5 | 6 | Принимает только 2 возможных значения `True / False` 7 | 8 | На удивление занимает больше места чем можно себе представить, 9 | занимает `28 байт`, из-за того что в питоне все является объектом, 10 | и на каждый объект ведется подсчет ссылок, и для самих ссылок 11 | требуется место, да еще и каждый объект реализует массу магических 12 | методов, да и наследуется от главного объекта `object`, по итогу 13 | он занимает `28 байт`. 14 | 15 | `Boolean` может использоваться как результат сравнения, даже без 16 | использования оператора `if` 17 | 18 | ```python 19 | a = 'qwe' 20 | b = 'qwe' 21 | d = 'fgs' 22 | 23 | c = a == b 24 | g = a == d 25 | 26 | print(c) 27 | 28 | # Вывод 29 | # True 30 | # False 31 | ``` 32 | -------------------------------------------------------------------------------- /Theory/Part_2/Data_types.md: -------------------------------------------------------------------------------- 1 | Примитивные типы данных 2 | --- 3 | 1) `Integer` - обычные целые числа 4 | 2) `Float` - Числа с плавающей точкой 5 | 3) `Boolean` - Истина или Ложь, `True / False` 6 | 4) `String` - Неизменяемые, Последовательности 7 | 5) `None` - Неопределенное значение 8 | --- 9 | 10 | Структур данных 11 | --- 12 | 1) `list` Списки - Изменяемые, Последовательности 13 | 2) `set` Множества - Изменяемые, Последовательности 14 | 3) `dict` Словари - Изменяемые, Последовательности 15 | 4) `frozenset` Множества - Неизменяемые множества 16 | 5) `tuple` Кортеж - Неизменяемые 17 | --- 18 | 19 | Функции для проверки типа данных 20 | --- 21 | 22 | 1) `type()` - Узнать тип данных. 23 | 24 | 2) `isinstance()` - Проверка, является ли объект нужного типа данных. 25 | 26 | 3) `issubclass()` - Проверка, является ли объект дочерним по отношению 27 | к определенному классу. 28 | 29 | Все классы наследуются от базового `object` данный метод проверяет 30 | являться ли указанный класс наследником. 31 | 32 | ```python 33 | class Point: 34 | def __init__(self, x, y): 35 | self.x = x 36 | self.y = y 37 | 38 | print(issubclass(Point, object)) 39 | 40 | # Вывод 41 | # True 42 | ``` 43 | 44 | 1) Первый аргумент - класс для проверки 45 | 2) Второй аргумент - класс родитель 46 | 47 | Возвращает `True / False` 48 | 49 | --- 50 | 51 | Важно понимать 52 | --- 53 | 54 | Если у изменяемого значения больше одного имени, и это значение 55 | изменяется, то изменяются все имена. Если есть множество 56 | символических ссылок(имен переменных) которые ссылаются на одно 57 | изменяемое значение, и мы меняем это значение, то все ссылки будут 58 | указывать на это измененное значение. 59 | 60 | Если есть имена указывающие на одно не изменяемое значение, и мы 61 | меняем одно из значений переменной, то именно эта переменная будет 62 | ссылаться на абсолютно новое значение, на совершенно новую ячейку 63 | памяти, этом и есть сама суть изменяемых и не изменяемых типов данных. 64 | -------------------------------------------------------------------------------- /Theory/Part_2/Integer_float.md: -------------------------------------------------------------------------------- 1 | Integer 2 | --- 3 | --- 4 | 5 | Функции `int()` и `float()` используются для превращения строки 6 | или числа в соответствующий тип данных. 7 | 8 | `int` - тип с произвольной точностью, к что можно производит 9 | вычисления с огромными числами: 10 | 11 | ```python 12 | print(23423423324235325345353453453453453434534553534534534**23) 13 | 14 | # Вывод 15 | # 3176570138216911739091212499933062068970237146187861775218324230 16 | # 0864627905744930245741026835993629437346965792527513768359030778 17 | # 8573391214780477871811737552927333509853638485224391523504587460 18 | # 5776590246602826957114902353211577889058134114170456304429767979 19 | # 799220653 20 | ``` 21 | 22 | --- 23 | 24 | Бесконечное число 25 | --- 26 | 27 | Есть 2 способа представить бесконечное число, либо с помощью модуля 28 | `math.inf` который возвращает бесконечное число, либо с помощью 29 | метода `float()` 30 | 31 | ```python 32 | import math 33 | max_infinity = math.inf 34 | min_infinity = -math.inf 35 | 36 | max_infinity = float("inf") 37 | min_infinity = float("-inf") 38 | ``` 39 | 40 | Обычно функция `float()` используется для превращения целого числа, или 41 | строки(которая содержит только числа) в тип `float`, но для создания 42 | именно бесконечно большого/малого числа, функция должна принимать 43 | строку `inf` или `-inf` 44 | 45 | --- 46 | 47 | Визуальный разделитель для чисел 48 | --- 49 | 50 | Для визуального разделения чисел можно использовать нижнее 51 | подчеркивание, это никак не влияет на работу кода, все то же самое, 52 | просто для удобства. 53 | 54 | ```python 55 | b = 10000000 56 | c = 10_000_000 57 | 58 | print('b = ', b, '\nid(b) = ', id(b)) 59 | print('c = ', c, '\nid(c) = ', id(c)) 60 | print('c == b : ', c == b) 61 | print('c is b : ', c is b) 62 | 63 | # Вывод 64 | # b = 10000000 65 | # id(b) = 140058589259792 66 | # c = 10000000 67 | # id(c) = 140058589259792 68 | # c == b : True 69 | # c is b : True 70 | ``` -------------------------------------------------------------------------------- /Theory/Part_2/None.md: -------------------------------------------------------------------------------- 1 | None 2 | --- 3 | --- 4 | 5 | None - это класс у которого реализован паттерн `singlton`, так что 6 | есть только один `None` все программы, и его проверка на самого 7 | себя вернет `True` 8 | 9 | ```python 10 | print('Проверка по значнеию None == None', None == None) 11 | print('Проверка по ссылке None == None', None is None) 12 | 13 | # Вывод 14 | # True 15 | # True 16 | ``` 17 | 18 | Тип данных `None` занимает `16 байт`, является классом и реализует 19 | паттерн `singlton` 20 | 21 | ```python 22 | import sys 23 | 24 | var = None 25 | 26 | memory = sys.getsizeof(var) 27 | 28 | print(var.__sizeof__()) 29 | print(memory) 30 | 31 | # Вывод 32 | # 16 33 | # 16 34 | ``` 35 | -------------------------------------------------------------------------------- /Theory/Part_2/Tuple.md: -------------------------------------------------------------------------------- 1 | Кортежи - `tuple` 2 | --- 3 | 4 | Кортежи по сути полностью идентичен спискам, тоже являются 5 | последовательностями, главное их отличие это неизменяемость. 6 | 7 | Определение такое же как и у списков, но через круглые скобки: 8 | 9 | ```python 10 | my_tuple = (1, "hello", 3.14) 11 | ``` 12 | 13 | Доступ к элементам происходит по индексу как и у списков: 14 | 15 | ```python 16 | print(my_tuple[0]) 17 | 18 | # Вывод 19 | # 1 20 | ``` 21 | 22 | Поддерживают 2 способа создания кортежей, как с обозначением 23 | скобок, так и без них. 24 | 25 | ```python 26 | my_tuple1 = (1, 3.14, "Hello World!") 27 | my_tuple2 = 1, 1, "one", "one", "one", "two", 3 28 | ``` 29 | 30 | --- 31 | 32 | Методы кортежей 33 | --- 34 | 35 | 1) `my_tuple.index()` - Принимает значение и возвращает индекс по 36 | которому оно находится в кортеже. 37 | 38 | ```python 39 | my_tuple = (1, 3.14, "Hello World!") 40 | 41 | print('index of 3.14 = ', my_tuple.index(3.14)) 42 | print('index of "Hello World!" = ', my_tuple.index("Hello World!")) 43 | 44 | # index of 3.14 = 1 45 | # index of "Hello World!" = 2 46 | ``` 47 | 48 | 2) `my_tuple.count()` - Принимает значение и возвращает количество 49 | раз которое это значение содержится в кортеже. 50 | 51 | ```python 52 | my_tuple = (1, 3.14, 1, 34, 1, "Hello World!") 53 | 54 | print('count of number 1 = ', my_tuple.count(1)) 55 | 56 | # count of number 1 = 3 57 | ``` -------------------------------------------------------------------------------- /Theory/Part_3/Arithmetic.md: -------------------------------------------------------------------------------- 1 | Арифметические операции (`+`, `-`, `*`, `/`, `//`, `%`, `**`) 2 | --- 3 | --- 4 | 5 | Обычные операции типа сложения, вычитания и умножения, работают, 6 | как всегда, результатом действий с типами `int` всегда будет `int`. 7 | 8 | ```python 9 | # Сложение 10 | print('5 + 3 = ', 5 + 3) 11 | 12 | # Вычитание 13 | print('20 - 5 = ', 20 - 5) 14 | 15 | # Умножение 16 | print('5 * 5 = ', 5 * 5) 17 | 18 | # Вывод 19 | # 5 + 3 = 8 20 | # 20 - 5 = 15 21 | # 5 * 5 = 25 22 | ``` 23 | 24 | Деление работает немного иначе, даже если типами являются `int` то в 25 | результате всегда получим тип `float`. 26 | 27 | ```python 28 | # Деление 29 | print('10 / 5 = ', 10 / 5) 30 | print('5 / 3 = ', 5 / 3) 31 | 32 | # Деление 33 | # 10 / 5 = 2.0 34 | # 5 / 3 = 1.6666666666666667 35 | ``` 36 | 37 | --- 38 | Два символа `**` говорят о возведении в степень: 39 | 40 | ```python 41 | print('2 ** 2 = ', 2**2) 42 | print('2 ** 3 = ', 2**3) 43 | 44 | # Вывод 45 | # 2 ** 2 = 4 46 | # 2 ** 3 = 8 47 | ``` 48 | 49 | --- 50 | 51 | Деление без остатка `//`, указание 2 символов косой черты, указывает 52 | на деление и возвращает целочисленное значение, убирая цифры после 53 | точки. 54 | 55 | ```python 56 | print('2 // 3 = ', 2//3) 57 | print('3 // 3 = ', 3//3) 58 | print('4 // 3 = ', 4//3) 59 | 60 | # Вывод 61 | # 2 // 3 = 0 62 | # 3 // 3 = 1 63 | # 4 // 3 = 1 64 | ``` 65 | 66 | При обычном делении `4 / 3` получим `1.33333` но при делении без остатка, 67 | все после точки откидывается, если делимое равно делителю то ответ `1`, 68 | а если делимое меньше делителя то ответ и вовсе `0`, в любом случае 69 | ответом всегда будет целочисленный тип `int`. 70 | 71 | --- 72 | Деление по Модулю, остаток от деления `%` 73 | 74 | ```python 75 | print('5 % 3 = ', 5%3) 76 | print('10 % 3 = ', 10%3) 77 | print('10 % 3.3 = ', 10%3.3) 78 | 79 | # Вывод 80 | # 5 % 3 = 2 81 | # 10 % 3 = 1 82 | # 10 % 3.3 = 0.10000000000000053 83 | ``` 84 | 85 | Эта операция противоположна делению без остатка, она возвращает часть 86 | после точки, игнорируя целую часть, тип ответа может быть `int` 87 | или `float` в зависимости от того есть ли среди операндов тип `float` 88 | -------------------------------------------------------------------------------- /Theory/Part_3/Assigment.md: -------------------------------------------------------------------------------- 1 | Оператор присваивания `=`, `+=`, `-=`, `/=`, `//=` 2 | --- 3 | 4 | Все возможные операторы присваивания работают как обычные 5 | математические операции, но с последующим присвоением результата 6 | переменной. 7 | 8 | ```python 9 | a = 10 10 | print('a = ', a) 11 | 12 | a += 5 13 | print('10 + 5 = ', a) 14 | 15 | a -= 3 16 | print('15 - 3 = ', a) 17 | 18 | a /= 3 19 | print('12 / 3 = ', a) 20 | 21 | a *= 3 22 | print('4 * 3 = ', a) 23 | 24 | a //= 6 25 | print('12 / 6 = ', a) 26 | 27 | a **= 4 28 | print('2 ** 4 = 2 * 2 * 2 * 2 = ', a) 29 | 30 | a %= 3 31 | print('16 % 3 = ', a) 32 | 33 | # Вывод 34 | # a = 10 35 | # 10 + 5 = 15 36 | # 15 - 3 = 12 37 | # 12 / 3 = 4.0 38 | # 4 * 3 = 12.0 39 | # 12 / 6 = 2.0 40 | # 2 ** 4 = 2 * 2 * 2 * 2 = 16.0 41 | # 16 % 3 = 1.0 42 | ``` 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Theory/Part_3/Bitwise.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Theory/Part_3/Bitwise.md -------------------------------------------------------------------------------- /Theory/Part_3/Comparison.md: -------------------------------------------------------------------------------- 1 | Операторы сравнения `==`, `!=`, `>`, `<`, `>=`, `<=` 2 | --- 3 | --- 4 | 5 | Все операторы работают интуитивно понятно, если проверка ведется 6 | с числами 1 и 0 то работает это след образом, 1 всегда равен True, 7 | а 0 всегда равен False. 8 | 9 | ```python 10 | print('4 < 5 = ', 4 < 5) 11 | print('10 > 5 = ', 10 > 5) 12 | print('7 <= 7 = ', 7 <= 7) 13 | print('0 >= 0 = ', 0 >= 0) 14 | print('3 == 3 = ', 3 == 3) 15 | print('3 == 3.0 = ', 3 == 3.0) 16 | 17 | print('1 == True = ', 1 == True) 18 | print('7 == True = ', 7 == True) 19 | print('0 == False = ', 0 == False) 20 | 21 | print('1 != 10 = ', 1 != 10) 22 | 23 | # Вывод 24 | # 4 < 5 = True 25 | # 10 > 5 = True 26 | # 7 <= 7 = True 27 | # 0 >= 0 = True 28 | # 3 == 3 = True 29 | # 3 == 3.0 = True 30 | 31 | # 1 == True = True 32 | # 7 == True = False 33 | # 0 == False = True 34 | 35 | # 1 != 10 = True 36 | ``` 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Theory/Part_3/Identity.md: -------------------------------------------------------------------------------- 1 | Операторы тождественности `is`, `is not` 2 | --- 3 | --- 4 | 5 | Эти операторы проверяют, занимает ли обьект одно и тоже место в 6 | памяти, по сути это проверка на соответствия типов сверяемых 7 | обьектов. 8 | 9 | Если есть число 5, то оно не равно числу 10 при проверке == 10 | ибо это есть проверка по значению, но проверка is сравнивает 11 | типы данных, а тип что у числа 5 что у числа 10 одинаковый. 12 | 13 | ```python 14 | if 5 == 5: 15 | print('5 == 5 = ', True) 16 | 17 | if 5 is 5: 18 | print('5 is 5 = ', True) 19 | 20 | if 5.0 == 5: 21 | print('5.0 == 5 = ', True) 22 | 23 | if 1 == True: 24 | print('1 == True = ', True) 25 | 26 | if 1 is True: 27 | print('1 is True = ', True) 28 | else: 29 | print('1 is True = ', False) 30 | 31 | # Вывод 32 | # 5 == 5 = True 33 | # 5 is 5 = True 34 | # 5.0 == 5 = True 35 | # 1 == True = True 36 | # 1 is True = False 37 | ``` 38 | 39 | --- 40 | 41 | `is` - Это оператор для проверки обьектов по ссылке а не по 42 | значению, в то время как `==` сравнивает обьекты именно по 43 | значению. 44 | -------------------------------------------------------------------------------- /Theory/Part_3/Logical.md: -------------------------------------------------------------------------------- 1 | Логические операторы `and`, `or`, `not` 2 | --- 3 | --- 4 | 5 | Если оба выражения с 2 сторон от оператора and верны, то 6 | выражение считается истинным. 7 | 8 | ```python 9 | if 7 > 1 and 5 > 3: 10 | print('ДА') 11 | else: 12 | print('НЕТ') 13 | 14 | a = 7 > 5 and 2 > 1 15 | print(a) 16 | 17 | # Вывод 18 | # ДА 19 | # True 20 | ``` 21 | --- 22 | 23 | Если оба выражения ложные, то только тогда все выражение 24 | считается ложным, если хотя бы одно из них верное, то и все 25 | выражение считается истинным. 26 | 27 | ```python 28 | a = 7 > 7 or 2 > -1 29 | print(a) 30 | 31 | # Вывод 32 | # True 33 | ``` 34 | 35 | --- 36 | 37 | Оператор not инвертирует булево выражение, True становится 38 | False, а False становится True. 39 | 40 | ```python 41 | if not False: 42 | print('да') 43 | else: 44 | print('нет') 45 | 46 | # Вывод 47 | # да 48 | ``` 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Theory/Part_3/Membership.md: -------------------------------------------------------------------------------- 1 | Операторы принадлежности `in`, `not in` 2 | --- 3 | --- 4 | 5 | Эти операторы проверяют, является ли значение частью 6 | последовательности, возвращает True / False. 7 | 8 | ```python 9 | list_str = ['ferret', 'cat', 'dog'] 10 | 11 | print('list_str = ', list_str) 12 | print('"fox" in list_str = ', 'fox' in list_str) 13 | print('"dog" in list_str = ', 'dog' in list_str) 14 | 15 | # Вывод 16 | # list_str = ['ferret', 'cat', 'dog'] 17 | # "fox" in list_str = False 18 | # "dog" in list_str = True 19 | ``` 20 | 21 | В python строки это последовательности элементов, как и 22 | списки, так что можно проверять наличие подстроки в строке, 23 | при помощи оператора `in` 24 | 25 | ```python 26 | print('me' in 'disappointment') 27 | 28 | # Вывод 29 | # True 30 | ``` 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Theory/Part_4/Break.md: -------------------------------------------------------------------------------- 1 | Прерывание `break` 2 | --- 3 | --- 4 | `break` - оператор прерывания цикла, если есть некий цикл, в 5 | ходе его работы можно предварительно закончить цикл и выйти из 6 | него, после срабатывания оператора `break` цикл полностью 7 | завершается в отличии, от оператора `continue`. 8 | 9 | ```python 10 | for i in range(1, 11): 11 | if i == 5: 12 | print('i == 5 тут прерывание break') 13 | break 14 | print('i = ', i) 15 | 16 | # Вывод 17 | # i = 1 18 | # i = 2 19 | # i = 3 20 | # i = 4 21 | # i == 5 тут прерывание break 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /Theory/Part_4/Continue.md: -------------------------------------------------------------------------------- 1 | Прерывание `continue` 2 | 3 | `continue` - Блок срабатывает таким же образом как и блок `break` 4 | нов отличии от него, не завершает ход цикла полностью, а только 5 | пропускает текущую итерацию цикла. 6 | 7 | ```python 8 | for i in range(1, 11): 9 | if i == 5: 10 | print('i == 5 тут прерывание continue') 11 | continue 12 | print('i = ', i) 13 | 14 | # Вывод 15 | # i = 1 16 | # i = 2 17 | # i = 3 18 | # i = 4 19 | # i == 5 тут прерывание continue 20 | # i = 6 21 | # i = 7 22 | # i = 8 23 | # i = 9 24 | # i = 10 25 | ``` -------------------------------------------------------------------------------- /Theory/Part_4/If_else.md: -------------------------------------------------------------------------------- 1 | Условие `if`, `elif`, `else` 2 | --- 3 | 4 | Когда выполняется инструкция `if`, проверяется условие, 5 | если условие истинно, тогда все инструкции в блоке `if` 6 | выполняются. Но если условие оказывается неверным, 7 | тогда все инструкции внутри этого блока пропускаются. 8 | 9 | ```python 10 | if True: 11 | print('Вы это видите') 12 | if 0: 13 | print('то вы не увидите') 14 | 15 | # Вывод 16 | # Вы это видите 17 | ``` 18 | 19 | --- 20 | 21 | Условие `else` исполняется если блок `if` не проходит проверку на 22 | истинность. 23 | 24 | ```python 25 | var = int(input('Введите число: ')) 26 | if var >= 10: 27 | print('Число {0} больше или равно 10'.format(var)) 28 | else: 29 | print('Число {0} меньше чем 10'.format(var)) 30 | 31 | # Вывод 32 | 33 | # Введите число: 1 34 | # Число 1 меньше чем 10 35 | 36 | # Введите число: 10 37 | # Число 10 больше или равно 10 38 | 39 | # Введите число: 123 40 | # Число 123 больше или равно 10 41 | ``` 42 | 43 | --- 44 | 45 | Оператор `if-elif-else` — это альтернативное представление 46 | оператора `if-else`, которое позволяет проверять несколько 47 | условий, вместо того чтобы писать вложенные `if-else`. 48 | 49 | ```python 50 | score = int(input("Введите вашу оценку: ")) 51 | 52 | if score >= 90: 53 | print("Отлично! Ваша оценка А") 54 | elif score >= 80: 55 | print("Здорово! Ваша оценка - B") 56 | elif score >= 70: 57 | print("Хорошо! Ваша оценка - C") 58 | elif score >= 60: 59 | print("Ваша оценка - D. Стоит повторить материал.") 60 | else: 61 | print("Вы не сдали экзамен") 62 | 63 | # Вывод 64 | # Введите вашу оценку: 100 65 | # Отлично! Ваша оценка А 66 | ``` 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Theory/Part_4/Ternary_operator.md: -------------------------------------------------------------------------------- 1 | Тернарный оператор 2 | --- 3 | --- 4 | 5 | Оператор для работы с 3 переменными, по сути это просто `if-else` 6 | но в одну строчку: 7 | 8 | [если истина] if [выражение] else [если ложь] 9 | 10 | Проверка, является ли содержимое переменной var больше чем 100 11 | 12 | ```python 13 | var = 500 14 | result = True if var >= 100 else False 15 | print(f'var = {var} result = {result}') 16 | 17 | # Вывод 18 | # var = 500 result = True 19 | ``` 20 | 21 | Поиск наибольшего значения среди 2 чисел. 22 | 23 | ```python 24 | x, y = 25, 50 25 | big = x if x > y else y 26 | 27 | # Вывод 28 | # print(big) 29 | ``` 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Theory/Part_4/Try.md: -------------------------------------------------------------------------------- 1 | Блок `try` и `except` 2 | --- 3 | --- 4 | 5 | Блок `try` и `except` применяется для перехвата возникающих 6 | исключений, во время работы программы, в блоке `try` мы выполняем 7 | инструкцию в которой может возникнуть ошибка, если ее не происходит, 8 | то программа идет дальше, если же возникает исключение, то 9 | исполняется блок `except` в котором можно определить поведение в 10 | случае ошибки. 11 | 12 | Делить на `0` нельзя, и в процессе работы кода возникнет ошибка, 13 | `except` перехватывает это исключение и задает переменной 14 | значение `0` 15 | 16 | ```python 17 | try: 18 | k = 1 / 0 19 | except ZeroDivisionError: 20 | k = 0 21 | print(k) 22 | 23 | # Вывод 24 | # 0 25 | ``` 26 | --- 27 | Мы можем указывать какое именно исключение следует перехватывать, 28 | отлавливая исключение мы перехватываем и всех его потомков, 29 | например, перехватывая `ArithmeticError`, мы также перехватываем 30 | `FloatingPointError`, `OverflowError` и `ZeroDivisionError`. 31 | 32 | Если не указывать блоку `except` ничего, то он будет перехватывать 33 | все исключения, то есть так тоже сработает: 34 | 35 | ```python 36 | try: 37 | k = 1 / 0 38 | except: 39 | k = 0 40 | 41 | print(k) 42 | 43 | # Вывод 44 | # 0 45 | ``` 46 | --- 47 | К конструкции перехвата исключений, также срабатывает блок 48 | `else` и `finally`. 49 | 50 | `finally` - Выполняет блок инструкций в любом случае, было 51 | исключение или нет. 52 | 53 | `else` - Выполняется если исключения не было. 54 | 55 | То есть если есть блок `finally` то он сработает в любом случае, 56 | если есть блок `else` и было исключение то все равно сработает 57 | только блок `finally` ибо `else` работает в случае если ошибки 58 | не было, если же есть `else` и `finally` и ошибки не было, то 59 | с начала сработает блок `else` а уже потом `finally`. 60 | 61 | Пример с исключением: 62 | ```python 63 | try: 64 | k = 1 / 0 65 | except ZeroDivisionError: 66 | print('Сработало исключение ZeroDivisionError') 67 | else: 68 | print('Сработал блок else') 69 | finally: 70 | print('Сработал блок finally') 71 | 72 | # Вывод 73 | # Сработало исключение ZeroDivisionError 74 | # Сработал блок finally 75 | ``` 76 | 77 | Пример без исключения: 78 | ```python 79 | try: 80 | k = 1 / 10 81 | except ZeroDivisionError: 82 | print('Сработало исключение ZeroDivisionError') 83 | else: 84 | print('Сработал блок else') 85 | finally: 86 | print('Сработал блок finally') 87 | 88 | # Вывод 89 | # Сработал блок else 90 | # Сработал блок finally 91 | ``` -------------------------------------------------------------------------------- /Theory/Part_4/While.md: -------------------------------------------------------------------------------- 1 | Цикл `while` 2 | --- 3 | --- 4 | В то время как `for` итерируется по последовательности ровно 5 | столько, сколько есть элементов в последовательности, в то время 6 | как цикл `while` работает до тех пор, пока верно некое условие. 7 | 8 | Мы можем итерироваться по возрастанию и по убыванию. 9 | ```python 10 | iter = 10 11 | while iter >= 0: 12 | print(iter) 13 | iter -= 1 14 | 15 | iter = 0 16 | while iter <= 10: 17 | print(iter) 18 | iter += 1 19 | 20 | # Вывод 21 | # 10 9 8 7 6 5 4 3 2 1 0 22 | # 0 1 2 3 4 5 6 7 8 9 10 23 | ``` 24 | -------------------------------------------------------------------------------- /Theory/Part_5/Default_function_arguments.md: -------------------------------------------------------------------------------- 1 | Инициализация аргументов по умолчанию 2 | --- 3 | 4 | У нас есть возможность задавать аргументам значение по умолчанию, 5 | но эта инициализация происходит только один раз в момент компиляции 6 | в байт-код, и далее они обновляться не будут, каждый новый вызов 7 | функции будет сохранять эти аргументы по умолчанию, они будут 8 | сохранены в атрибуте `function.__defaults__` этот атрибут содержит 9 | кортеж с аргументами по умолчанию. 10 | 11 | `function.__defaults__` - атрибут содержит кортеж с аргументами 12 | функции по умолчанию. 13 | 14 | Если аргументами по умолчанию являются неизменяемые типы, то все 15 | в порядке, от вызова функции к вызову функции они меняться не будут, 16 | но в случае если это изменяемый тип, то тут может возникнуть 17 | проблема, потому что тут от вызова к вызову эти аргументы по 18 | умолчанию будут меняться. 19 | 20 | Рассмотрим такой пример кода, тут по умолчанию есть множество, 21 | от вызова к вызову это множество меняется, потому что множество 22 | изменяемый тип, так что тут надо быть аккуратным. 23 | 24 | ```python 25 | def unique(iterable, seen=set()): 26 | acc = [] 27 | for item in iterable: 28 | if item not in seen: 29 | seen.add(item) 30 | acc.append(item) 31 | return acc 32 | 33 | xs = [1, 1, 2, 3] 34 | print(unique(xs)) 35 | 36 | print('Аргументы по умолчанию', unique.__defaults__) 37 | 38 | xs = [1, 1, 2, 3, 4, 5, 6, 7] 39 | print(unique(xs)) 40 | 41 | print('Аргументы по умолчанию', unique.__defaults__) 42 | 43 | # Вывод 44 | # [1, 2, 3] 45 | # Аргументы по умолчанию ({1, 2, 3},) 46 | # [4, 5, 6, 7] 47 | # Аргументы по умолчанию ({1, 2, 3, 4, 5, 6, 7},) 48 | ``` 49 | 50 | **Вывод: стоит избегать в качестве аргументов по умолчанию 51 | изменяемые типы данных.** 52 | 53 | **Как тогда поступить ?** 54 | Поступать стоит так, в качестве аргумента по умолчанию все таки 55 | использовать неизменяемый тип данных, а после в самой функции 56 | ее инициализировать, к примеру можно сделать так: 57 | 58 | ```python 59 | def unique(iterable, seen=None): 60 | acc = [] 61 | seen = set(seen or []) 62 | 63 | for item in iterable: 64 | 65 | if item not in seen: 66 | seen.add(item) 67 | acc.append(item) 68 | 69 | return acc 70 | ``` 71 | 72 | Эта строчка `seen = set(seen or [])` задает множество, либо то 73 | что было передано, либо полностью пустое, то есть None интерпретируется 74 | как false мы получаем пустое множество, а если множество было передано 75 | то оно и вставляется. -------------------------------------------------------------------------------- /Theory/Part_5/Function_closures.md: -------------------------------------------------------------------------------- 1 | Замыкания 2 | --- 3 | Замыкание - это выполнение функции с той областью видимости, не в 4 | которой она вызывается, а в которой она определена. 5 | 6 | Создаем функцию `strip_string(chars)` которая принимает строчку, 7 | и внутри функции определяем еще одну функцию `inner_function(string)` 8 | которая тоже принимает строчку, из функции верх уровня мы возвращаем 9 | функцию нижнего уровня, то есть ссылку на нее: 10 | 11 | ```python 12 | def strip_string(chars): 13 | def inner_function(string:str): 14 | return string.strip(chars) 15 | return inner_function 16 | 17 | x1 = strip_string('!') 18 | print('Работа с замыканиями 1:', x1("!Hello World!")) 19 | 20 | 21 | x2 = strip_string('!') 22 | print('Работа с замыканиями 2:', x2("!Helorld!")) 23 | 24 | # Вывод 25 | # Работа с замыканиями 1: Hello World 26 | # Работа с замыканиями 2: Helorld 27 | ``` 28 | 29 | В дальнейшем каждый раз вызывая ее мы будем получать ссылку на функцию 30 | нижнего уровня, и вызывая ее в работу она будет исполняться в контексте 31 | тех данных что были переданы в функцию верхнего уровня. 32 | 33 | И каждый из экземпляров будет работать в своем контексте. -------------------------------------------------------------------------------- /Theory/Part_5/Function_lambda.md: -------------------------------------------------------------------------------- 1 | Специальные функции `lambda`, `map`, `filter`, `zip` 2 | --- 3 | --- 4 | 5 | 6 | Функциональное программирование 7 | --- 8 | В основном питоне это не Функциональный язык программирования, 9 | в питоне есть `lambda` функции, но используются они не часто, и 10 | если используются то для решения простейших задач. 11 | 12 | Обычные функции именованы, `lambda` это тоже функция, но не 13 | именованная, так что при получении ошибки мы не увидим ее имени. 14 | 15 | Основные инструменты функционального в питоне: 16 | 17 | 1) `lambda` 18 | 2) `map` 19 | 3) `filter` 20 | 4) `zip` 21 | 22 | --- 23 | 24 | `filter` Функция 25 | --- 26 | 27 | `filter` - специальная функция, что как и `map` применяет 28 | функцию к некоторой последовательности, но если `map` применяла 29 | функцию к каждому элементу и возвращала все элементы 30 | последовательности, то функция `filter` не меняет элементы 31 | последовательности, но использует полученную функцию для 32 | сортировки элементов. 33 | 34 | Как и `map` функция `filter` возвращает особый обьект который 35 | требуется явно привести к структуре. 36 | 37 | Функция на основе которой будет происходить фильтрация должна 38 | возвращать `True / False` таким образом эта функция будет 39 | применена к каждому элементу последовательности, и в 40 | отфильтрованные попадут только те значения для которых 41 | было возвращено `True` 42 | 43 | --- 44 | 45 | Пример №1 46 | 47 | Создадим фильтр, который будет фильтровать список на 48 | положительные значения. 49 | 50 | ```python 51 | def filter_plus(number): 52 | if number > 0: 53 | return True 54 | return False 55 | 56 | some_list = [-10, -7, -5, 0, 1, 4, 5, 7, 12] 57 | 58 | result = list(filter(filter_plus, some_list)) 59 | print(result) 60 | 61 | # Вывод 62 | # [1, 4, 5, 7, 12] 63 | ``` 64 | 65 | 66 | --- 67 | 68 | `lambda` Функция 69 | --- 70 | Это анонимная функция, по сути представляет собой выражение, 71 | используется для удобной замены меленький стандартных функций, 72 | `lambda` автоматически применяет оператор `return` к результату 73 | вычисления. 74 | 75 | Лямбда принимает любое количество аргументов (или ни одного), 76 | но состоит из одного выражения. 77 | 78 | lambda arguments: expression 79 | 80 | Иметь `lambda` функции из нескольких строк кода нельзя, 81 | только одно выражение. 82 | 83 | --- 84 | 85 | Стандартная запись функций, требует создание функции и ее 86 | использование, к примеру след образом. 87 | 88 | ```python 89 | def make_sum(x, y): 90 | return x + y 91 | 92 | print(make_sum(1, 2)) 93 | 94 | # Вывод 95 | # 3 96 | ``` 97 | 98 | Замена предыдущей функции на `lambda` функцию: 99 | 100 | ```python 101 | make_sum = lambda x, y: x + y 102 | result = make_sum(1, 5) 103 | print(result) 104 | 105 | # Вывод 106 | # 6 107 | ``` 108 | 109 | Таким образом мы создали функцию в переменной, и используем ее как 110 | функцию, однако `PEP` - рекомендации по работе с кодом питона, не 111 | советует использование `lambda` функций как полноценную замену 112 | настоящим функциям. 113 | 114 | `lambda` функции обычно используются для замены некого одноразового 115 | действия с какой-либо структурой данных, примеру пройтись по всем 116 | элементам списка, и сделать некое простейшие действие. 117 | 118 | Проблема может заключаться в том что если мы постоянно используем 119 | `lambda` выражения и где-то в них произойдет ошибка, то поймать 120 | ее будет проблематично, `lambda` функция не имеет имени, так что вы 121 | не увидите в отладке название функции в которой произошла ошибка. 122 | 123 | --- 124 | 125 | Пример №1 126 | 127 | Простейшее использование, передаем в `lambda` 2 переменные, 128 | складываем и возвращаем результат: 129 | ```python 130 | some_lambda = lambda x, y: x + y 131 | print(some_lambda(10, 70)) 132 | 133 | # Вывод 134 | # 80 135 | ``` 136 | 137 | --- 138 | Пример №2 139 | 140 | Мы можем устанавливать значения по умолчанию, это полезно когда 141 | мы создаем функцию которая по умолчанию удваивает значение, но 142 | при необходимости можем передать второй аргумент. 143 | ```python 144 | some_lambda = lambda x, y=2: print(x*y) 145 | some_lambda(10) 146 | 147 | some_lambda = lambda x, y=2: print(x*y) 148 | some_lambda(10, 5) 149 | 150 | # Вывод 151 | # 20 152 | # 50 153 | ``` 154 | 155 | --- 156 | Пример №3 157 | 158 | Можно скомбинировать, `labmda` и `map` функции, `map` принимает 159 | 2 параметра, функцию которую требуется применить на некоторую 160 | последовательность, и саму последовательность, сделаем это, 161 | умножим на 2 каждый элемент последовательности, незабываем, 162 | что функция `map` возвращает особый объект типа `map` и 163 | его требуется явно превращать в последовательность. 164 | 165 | ```python 166 | some_list = [1, 2, 3, 4, 5] 167 | 168 | result_1 = list(map(lambda x: x*2, some_list)) 169 | print(result_1) 170 | 171 | # Вывод 172 | # [2, 4, 6, 8, 10] 173 | ``` 174 | 175 | --- 176 | 177 | Пример №4 178 | 179 | Можно использовать специальную функцию `filter` для фильтрации 180 | последовательности, совместно с функцией `lambda`. Напишем 2 181 | функции, одна фильтрует список и возвращает все четные 182 | элементы, другая после фильтрации возвращает нечетные элементы 183 | 184 | ```python 185 | 186 | some_list = [-5, -3, -1, 0, 1, 2, 3, 4, 5, 10, 20, 21] 187 | 188 | # Получить нечетные элементы 189 | result_1 = list(filter(lambda number: True if number % 2 else False, some_list)) 190 | 191 | # Получить четные элементы 192 | result_2 = list(filter(lambda number: False if number % 2 else True, some_list)) 193 | 194 | print('Получить нечетные элементы : ', result_1) 195 | print('Получить четные элементы : ', result_2) 196 | 197 | # Вывод 198 | # Получить нечетные элементы : [-5, -3, -1, 1, 3, 5, 21] 199 | # Получить четные элементы : [0, 2, 4, 10, 20] 200 | ``` 201 | -------------------------------------------------------------------------------- /Theory/Part_5/Functions.md: -------------------------------------------------------------------------------- 1 | Функция это все еще объект ! 2 | --- 3 | 4 | По скольку функция это все еще объект, мы можем присвоить этой 5 | функции атрибуты класса, и по скольку класс этого объекта-функции 6 | существует в не зависимости от объектов, тем самым мы создаем 7 | статическое значение принадлежащее этой функции: 8 | 9 | ```python 10 | def func(x): 11 | intermediate_var = x ** 2 + x + 1 12 | 13 | if intermediate_var % 2: 14 | y = intermediate_var ** 3 15 | else: 16 | y = intermediate_var ** 3 + 1 17 | 18 | # setting attributes here 19 | func.optional_return = intermediate_var 20 | func.is_awesome = 'Yes, my function is awesome.' 21 | 22 | return y 23 | 24 | y = func(3) 25 | print('Final answer is', y) 26 | 27 | # Accessing function attributes 28 | print('Show calculations -->', func.optional_return) 29 | print('Is my function awesome? -->', func.is_awesome) 30 | 31 | # Final answer is 2197 32 | # Show calculations --> 13 33 | # Is my function awesome? --> Yes, my function is awesome. 34 | ``` 35 | 36 | По началу функция не имеет атрибутов класса, но в процессе работы 37 | мы устанавливаем этой функции атрибут класса, и теперь можем 38 | обращаться к ней, устанавливать их можно как внутри функции, так 39 | и с наружи. 40 | 41 | Так образ можно к примеру сохранять предыдущие значения вычисления. 42 | 43 | --- 44 | 45 | Возвращаемое Функцией значение 46 | --- 47 | Если вывести что то в функции `print()` то оно будет напечатано, но 48 | если вывести `print()` в `print()` то ошибки не будет, а напечатано 49 | будет `None` 50 | 51 | ```python 52 | print(print("123")) 53 | 54 | # Вывод 55 | # None 56 | ``` 57 | 58 | Это происходит по причини того что любая функция всегда возвращает 59 | какое либо значение, и если мы не определили это поведение при помощи 60 | оператора `return` то функция всегда по стандарту возвращает `None` 61 | 62 | --- 63 | 64 | Хорошая практика 65 | --- 66 | 67 | Представим что создаем функцию которая должна сортировать приходящие 68 | аргументы. 69 | 70 | По скольку нам требуется чтобы было что сортировать, то нам 71 | необходимо чтобы в функцию приходил хотя бы один аргумент, для 72 | этого реализуем сразу `2` аргумента в функцию 73 | `def find_min(first, *args)` аргумент `first` обязательный аргумент 74 | так что мы точно получим хотя бы `1` аргумент для сортировки, а 75 | потом просто в условии цикла объединяем их в кортеж по которому 76 | будем идти `(first, ) + args` 77 | 78 | Таким образом мы обязуем передавать хотя бы `1` аргумент, и в то 79 | же время работаем с ними как с единым кортежем. 80 | 81 | ```python 82 | import math 83 | 84 | def find_min(first, *args, min_inf=-math.inf, max_inf=math.inf): 85 | result = max_inf 86 | for element in (first, ) + args: 87 | if element < result and min_inf < element < max_inf: 88 | result = element 89 | return max(result, min_inf) 90 | 91 | print(find_min(88, 12, 13, -5, min_inf=0, max_inf=255)) 92 | print(find_min(12, 13, -5)) 93 | 94 | # Вывод 95 | # 12 96 | # -5 97 | ``` -------------------------------------------------------------------------------- /Theory/Part_5/Packing_and_unpacking_function_arguments.md: -------------------------------------------------------------------------------- 1 | Упаковка и распаковка 2 | --- 3 | 4 | Когда мы передаем в функцию ряд неименованных аргументов, эти аргументы 5 | приходят в функцию в качестве соединенного кортежа, это называется 6 | упаковкой и указывается она при помощи символа звездочки `*args` 7 | 8 | Но есть и обратный процесс, распаковка, это процесс когда мы из 9 | структуры изымаем все ее элементы, то есть тут эти переменные уже 10 | не соединены некой структурой, просто ряд переменных, вот пример: 11 | 12 | ```python 13 | def function_1(*args): 14 | print('Пример с распаковкой:') 15 | print(type(args)) 16 | print(*args) 17 | 18 | def function_2(*args): 19 | print('\nПример без распаковки:') 20 | print(type(args)) 21 | print(args) 22 | 23 | function_1(1,2,3,4) 24 | function_2(1,2,3,4) 25 | 26 | # Вывод 27 | 28 | # Пример с распаковкой: 29 | # 30 | # 1 2 3 4 31 | 32 | # Пример без распаковки: 33 | # 34 | # (1, 2, 3, 4) 35 | ``` 36 | 37 | --- 38 | 39 | Интересное о присвоении данных аргументам функции 40 | --- 41 | 42 | Когда мы имеем список, на него есть ссылка через имя переменной, 43 | но когда мы передаем этот список в функцию, для функции создается 44 | ее локальная память, и поскольку список передается по ссылке, то 45 | теперь на наш список есть 2 ссылки, одна ссылается из вне из 46 | внешнего кода, а другая ссылка ссылается на список изнутри функции. 47 | 48 | Так изменение списка внутри функции повлияет на сам список и из вне, 49 | ибо список один, просто на него 2 ссылки, из вне и изнутри. 50 | 51 | Но, опять же, если внутри функции мы сделаем присвоение типа: 52 | 53 | ```python 54 | my_list = [1,2,3] 55 | 56 | def func(my_list): 57 | my_list = my_list + [4, 5] 58 | 59 | func(my_list) 60 | ``` 61 | 62 | То в таком случае, новый `my_list` внутри функции уже больше не будет 63 | ссылаться на внешний список, и его изменение не повлияет на внешний 64 | список. 65 | -------------------------------------------------------------------------------- /Theory/Part_6/Access_modifiers.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PopckovS/Python-Lessons/c0989d7cecb9c45a56a5882582459d750470f095/Theory/Part_6/Access_modifiers.md -------------------------------------------------------------------------------- /Theory/Part_6/Mechanism__slots__.md: -------------------------------------------------------------------------------- 1 | Механизм `__slots__` 2 | --- 3 | --- 4 | У обьектов есть специальный атрибут `__dict__` который содержит 5 | в себе словарь со всеми атрибутами обьекта, этот атрибут определен 6 | по дефолту. 7 | 8 | Также помимо этого мы можем сами обьявить в классе специальный 9 | атрибут `__slots__ = ['x', 'y', 'z']` создание этого атрибута 10 | автоматически не позволяет использовать `__dict__` по скольку 11 | атрибут `__slots__` фиксированный поиск элементов в нем статичны, 12 | это дает след преимущества: 13 | 14 | 1) У обьекта можно создавать только те атрибуты которые 15 | перечислены в `__slots__` 16 | 17 | 18 | 2) По скольку количество элементов фиксированное поиск элементов 19 | проходит значительно быстрее. 20 | 21 | Каждый элемент в `__slots__` хранится в заранее отведенном месте 22 | и по этому является **обьектом дескриптора** 23 | 24 | Реализация этого механизма полностью на языке `C` и потому очень 25 | эффективна. 26 | 27 | Если все таки нам требуется использовать `__dict__` совместно с 28 | `__slots__` то мы можем сделать это добавив `__dict__` а перечень 29 | `__slots__` 30 | 31 | Пример реализации: 32 | 33 | ```python 34 | class Point: 35 | 36 | __slots__ = ['x', 'y', '__dict__'] 37 | 38 | def __init__(self, x, y): 39 | self.x = x 40 | self.y = y 41 | 42 | def setCoords(self, x, y): 43 | self.x = x 44 | self.y = y 45 | 46 | def getCoords(self): 47 | return self.__slots__ 48 | 49 | 50 | pt = Point(10, 20) 51 | 52 | pt.x = 1 53 | pt.y = 2 54 | pt.z = 55 55 | 56 | print(pt.getCoords()) 57 | print(pt.z) 58 | 59 | # Вывод 60 | # ['x', 'y', '__dict__'] 61 | # 55 62 | ``` 63 | 64 | Также нельзя обь являть в слотах переменную класса, это 65 | даст ошибку. 66 | 67 | ```python 68 | STATIC_NAME = 'Статичное название' 69 | __slots__ = ['x', 'y', '__dict__', STATIC_NAME] 70 | ``` 71 | 72 | --- 73 | 74 | Атрибут `__slots__` 75 | --- 76 | 77 | По дефолту класс реализует атрибут `__dict__` это словарь в котором он 78 | будет содержать все атрибуты обьекта. 79 | 80 | Можно определить список или кортеж `__slots__` как атрибут класса, и 81 | обьявить в нем названия всех переменных которые можно обьявлять и 82 | использовать в обьекте такого класса, при этом атрибут `__dict__` 83 | автоматически не создается. 84 | 85 | Это позволяет экономить память в программе, у обьектов и атрибутов 86 | есть такой метод как `__sizeof__()` который возвращает размер 87 | затрачиваемой памяти на хранение данного элемента: 88 | 89 | ```python 90 | class One: 91 | """Заменяет __dict__ атрибутом __slots__""" 92 | __slots__ = ['x', 'y'] 93 | 94 | def __init__(self, x, y): 95 | self.x = x 96 | self.y = y 97 | 98 | def get_coord(self): 99 | return self.x, self.y 100 | 101 | class Two: 102 | """Имеет атрибут __dict__""" 103 | 104 | def __init__(self, x, y): 105 | self.x = x 106 | self.y = y 107 | 108 | def get_coord(self): 109 | return self.x, self.y 110 | 111 | x1 = One(10, 20) 112 | x2 = Two(100, 200) 113 | 114 | print('Класс с __slots__ :', x1.__sizeof__()) 115 | print('Класс с __dict__ :', x2.__sizeof__(), x2.__dict__.__sizeof__()) 116 | 117 | # Вывод 118 | # Класс с __slots__ : 32 119 | # Класс с __dict__ : 32 88 120 | ``` 121 | 122 | Как можно увидеть, класс у которого есть атрибут `__dict__` 123 | занимает на 88 байт памяти в кто время как у другого класса, 124 | атрибута `__dict__` вовсе нет и памяти он не занимает вообще. 125 | 126 | --- 127 | 128 | Оптимизация кода 129 | --- 130 | 131 | 1) Использование спец атрибута `__slots__` который может применять 132 | `list` или `tuple` их потребление памяти ниже чем у `dict` так образ 133 | снижается потребление памяти. 134 | 135 | 136 | ```python 137 | print('dict().__sizeof__() = ', dict().__sizeof__()) 138 | print('list().__sizeof__() = ', list().__sizeof__()) 139 | print('tuple().__sizeof__() = ', tuple().__sizeof__()) 140 | print('set().__sizeof__() = ', set().__sizeof__()) 141 | 142 | # Вывод 143 | # dict().__sizeof__() = 216 144 | # list().__sizeof__() = 40 145 | # tuple().__sizeof__() = 24 146 | # set().__sizeof__() = 200 147 | ``` 148 | 149 | 2) Использование слабых ссылок, слабые ссылки в отличие от обычных 150 | ссылок, говорят сборщику мусора, что объекты на которые ссылается 151 | слабая ссылка можно удалять в отличие от обычных ссылок которые. -------------------------------------------------------------------------------- /Theory/Part_6/Object_3.md: -------------------------------------------------------------------------------- 1 | Функторы 2 | --- 3 | 4 | Функторы - это класс в котором определили метод 5 | `__call__(self, *args, **kargs)` этот метод будет срабатывать 6 | когда объект класс пытаются вызвать как метод. 7 | 8 | ```python 9 | class StripChars: 10 | """Класс функтор, удаляет из строки все не нужные символы""" 11 | def __init__(self, chars): 12 | self.__chars = chars 13 | 14 | def __call__(self, *args, **kwargs): 15 | if not isinstance(args[0], str): 16 | raise ValueError("Аргумент должен быть строкой") 17 | return args[0].strip(self.__chars) 18 | 19 | sc = StripChars('!') 20 | print(sc('Hello World!')) 21 | 22 | # Вывод 23 | # Hello World 24 | ``` 25 | 26 | --- 27 | 28 | Методы объектов, `@classmethod` и `@staticmethod` 29 | --- 30 | 31 | Существует 3 метода, это может быть обычный динамический метод, 32 | который вызывается у объекта и имеет один обязательный метод `self` 33 | 34 | Также помимо них, существует 2 типа других методов, которые задаются 35 | при помоях декораторов. 36 | 37 | `@classmethod` - метод с таким декоратором требует получение аргумента 38 | `cls` который содержит в себе ссылку на этот класс, этого же можно 39 | добиться при помощи указания названия класса. 40 | 41 | ```python 42 | @classmethod 43 | def class_meythod(cls): 44 | return cls.STATIC_NAME 45 | ``` 46 | 47 | `@staticmethod` - обычный декоратор для метода, он не требует никаких 48 | специальных аргументов, и может обращаться к значениям класса при 49 | помощи указания названия этого класса. 50 | 51 | ```python 52 | @staticmethod 53 | def static_method(): 54 | return Point.STATIC_NAME 55 | ``` 56 | 57 | По существу это выглядит так, `@classmethod` - используется для 58 | методов которые будут работать с данными класса, а `@staticmethod` 59 | используется для операций тематически связанных к этим классом, 60 | однако в любом их них на самом деле можно делать что угодно, 61 | и работать с любыми объектами класса, если передать объект класса 62 | в эти методы, чтобы использовать его как заменитель `self` 63 | 64 | --- 65 | 66 | Статические методы 67 | --- 68 | 69 | Создаются при помощи декоратора `@staticmethod` и также метод 70 | более не требует использования параметра `self` 71 | 72 | Пример статического метода: 73 | 74 | ```python 75 | @staticmethod 76 | def getCounter(): 77 | return Point.__count 78 | ``` 79 | 80 | По скольку у метода более нет аргумента `self` мы более не можем 81 | оперировать к объектам, только к статике класса. 82 | 83 | Создадим класс, который будут при помощи статического атрибута считать 84 | количество экземпляров самого класса. 85 | 86 | ```python 87 | class Point: 88 | __count = 0 89 | 90 | def __init__(self, x, y): 91 | Point.__count += 1 92 | self.x = x 93 | self.y = y 94 | 95 | @staticmethod 96 | def getCounter(): 97 | return Point.__count 98 | 99 | pt1 = Point(1, 2) 100 | pt2 = Point(10, 20) 101 | 102 | def newGetCounter(): 103 | return 55 104 | 105 | pt1.getCounter = newGetCounter 106 | 107 | print(pt1.getCounter()) 108 | print(Point.getCounter()) 109 | 110 | # Вывод 111 | # 55 112 | # 2 113 | ``` 114 | 115 | Также можно увидеть на этом примере, что можно переопределить 116 | метод из вне, внеся в него значение другого метода. 117 | 118 | ```python 119 | def newGetCounter(): 120 | return 55 121 | 122 | pt1.getCounter = newGetCounter 123 | ``` 124 | 125 | Сделав это мы переопределили метод класса на другой. 126 | 127 | --- 128 | 129 | Перегрузка методов 130 | --- 131 | 132 | Перегрузка методов - Выполнять разный функционал в зависимости от 133 | количества переданных аргументов. 134 | 135 | Если в других языках типа `C#` это подразумевает еще и создание нового 136 | одноименного метода, то в Питоне это делается просто путем условий. 137 | 138 | К примеру так: 139 | 140 | ```python 141 | def setCoords(self, start:Point, end:Point=None): 142 | if end is None: 143 | if start.check_int(): 144 | self._start = start 145 | else: 146 | print("Координаты должны быть целочисленными") 147 | else: 148 | if start.check_int() and end.check_int(): 149 | Point.set_coord(self, start, end) 150 | else: 151 | print("Координаты должны быть целочисленными") 152 | ``` 153 | 154 | Таким образом мы теперь можем вызывать метод как с 2, так и с 1 арг. 155 | 156 | --- 157 | 158 | Абстрактные методы 159 | --- 160 | 161 | Абстрактные методы - методы которые должны быть обязательно 162 | реализованы в дочерних классах. 163 | 164 | Сделать это можно путем вызова исключения, метод будет всегда давать 165 | исключение, до тех пор пока его не переопределят, таким образом мы 166 | заставляем переопределить этот метод в дочерних классах. 167 | 168 | Пример реализации: 169 | 170 | ```python 171 | def drawLine(self): 172 | raise NotImplementedError( 173 | "В дочернем классе должен быть переопред метод drawLine()" 174 | ) 175 | ``` 176 | 177 | --- 178 | 179 | Классы-примеси `Mixin` 180 | --- 181 | В случае если есть класс экземпляры которого мы не хотим создавать 182 | самостоятельно(отдельно) то такой класс можно использовать 183 | для множественного наследования, такие классы называют примесями. 184 | 185 | **Классы `Mixin`** - классы которые сами по себе создавать мы не 186 | будем, и которые можно использовать для множественного наследования, 187 | наделяя их потомков нужным функционалом, то есть просто класс 188 | которые дает в реализацию некоторые методов. 189 | 190 | Классы примеси следует указывать первыми в дереве наследования, 191 | сам по себе примесь ничего не делает, работает только в сочетании 192 | с другим классом. 193 | -------------------------------------------------------------------------------- /Theory/Part_6/Pattern.md: -------------------------------------------------------------------------------- 1 | Паттерны программирвоания 2 | --- 3 | --- 4 | 5 | Паттерн 'Моносостояние' 6 | --- 7 | Моносостояние - это паттерн программирования при котором есть несколько 8 | объектов одного класса, и все экземпляры этого класса имеют одни 9 | общие атрибуты, любая работа в получении или изменении или удалении 10 | этих атрибутов, приводит к такому же изменению этих атрибутов у всех 11 | других экземпляров этого класса. 12 | 13 | То есть у нас есть несколько объектов одного и того же класса, и все эти 14 | объекты ссылаются на одни и теже данные. 15 | 16 | Реализация происходит через статический атрибут класса ссылка на который 17 | присваивается каждому новому созданному объекту. 18 | 19 | ```python 20 | class Monopattern(): 21 | __atributs = { 22 | 'id': 0, 23 | 'name': None 24 | } 25 | 26 | def __init__(self): 27 | self.__dict__ = Monopattern.__atributs 28 | 29 | x1 = Monopattern() 30 | x2 = Monopattern() 31 | 32 | print(f'x1:{x1.__dict__} x2:{x2.__dict__}') 33 | 34 | x1.id = 15 35 | x2.name = 'Hello world' 36 | 37 | print(f'x1:{x1.__dict__} x2:{x2.__dict__}') 38 | 39 | # Вывод 40 | # x1:{'id': 0, 'name': None} x2:{'id': 0, 'name': None} 41 | # x1:{'id': 15, 'name': 'Hello world'} x2:{'id': 15, 'name': 'Hello world'} 42 | ``` 43 | -------------------------------------------------------------------------------- /Theory/Part_6/Privacy.md: -------------------------------------------------------------------------------- 1 | Доступ к приватным атрибутам и методам обьекта 2 | --- 3 | 4 | Если атрибут принадлежит обьекту и является приватным, то в атрибуте 5 | `__dict__` нему можно иметь доступ так: 6 | 7 | ```python 8 | pt = Point() 9 | pt._Point__private 10 | ``` 11 | 12 | Но что дело до приватных методов ? Тут на самом дела все также обстоит, 13 | есть 2 метода один приватный другой публичный, приставка в виде одного 14 | underscore и названия Класса, поскольку каждый метод является по дефолту 15 | статичным, то увидеть его можно в атрибуте `__dict__` принадлежащем 16 | классу, а не обьекту: 17 | 18 | ```python 19 | class Point: 20 | def __init__(self, one, two): 21 | self._list = one 22 | self.__private = two 23 | 24 | def my_public_method(self): 25 | print('Публичный методв') 26 | 27 | def __my_private_method(self): 28 | print('Приватный методв') 29 | 30 | pt = Point([10, 20, 30], "Приватная переменная") 31 | 32 | Point.my_public_method(pt) 33 | Point._Point__my_private_method(pt) 34 | 35 | print(pt.__dict__) 36 | print('='*20) 37 | print(Point.__dict__) 38 | 39 | # Вывод 40 | # 41 | # Публичный методв 42 | # Приватный методв 43 | # {'_list': [10, 20, 30], '_Point__private': 'Приватная переменная'} 44 | # ==================== 45 | # { 46 | # 'my_public_method': 47 | # .Point.my_public_method at 0x7fd3471f1d90>, 48 | # 49 | # '_Point__my_private_method': 50 | # .Point.__my_private_method at 0x7fd3471f1e18>, 51 | # } 52 | ``` 53 | 54 | Тут есть оба метода и как ожидалось приватный скрыт с помощью 55 | специального префикса. 56 | 57 | --- 58 | 59 | Отсутствие настоящей защищенности/приватности в Python 60 | --- 61 | 62 | Обычно существует 3 модификатора доступа к атрибутам обьектов, 63 | публичный используется по дефолту, один underscore делает атрибут 64 | защищенным, и 2 underscore дают приватность. 65 | 66 | `protected` - не дает какого либо ограничения на доступ к атрибутам, 67 | защищенность здесь номинальная, существует лишь как соглашение среди 68 | программистов, не дает настоящей приватности. 69 | 70 | `private` - тут есть настоящий механизм защиты атрибутов от внешнего 71 | доступа, но есть одна хитрость. 72 | 73 | Допустим есть такой класс: 74 | 75 | ```python 76 | class Point: 77 | def __init__(self, x, y): 78 | self.x = x 79 | self._y = y 80 | 81 | pt = Point(10, 20) 82 | 83 | print("Point.__dict__ = ", Point.__dict__) 84 | print("pt.__dict__ = ", pt.__dict__) 85 | ``` 86 | 87 | Мы можем вывести атрибуты как обьекта так и класса, именно их 88 | спец атрибут `__dict__` который в виде словаря хранит в себе 89 | все атрибуты. 90 | 91 | У самого класса и у обьекта есть свои экземпляры этого атрибута. 92 | 93 | Когда мы выводим `__dict__` обьекта, то можем увидеть в нем наши 94 | атрибуты, что мы задали при инициализации нового обьекта класса: 95 | 96 | ```python 97 | pt.__dict__ = {'x': 10, '_y': 20} 98 | ``` 99 | 100 | Видим что все атрибуты тут и перечислены, что публичные, что 101 | защищенные, разница лишь в одном нижнем подчеркивании, теперь 102 | можно понять почему нет способа защиты от для protected атрибутов. 103 | 104 | Добавим в наш класс новый атрибут `__z` и сделаем ее приватной, 105 | тогда выведя `__dict__` можно увидеть следующие: 106 | 107 | ```python 108 | class Point: 109 | def __init__(self, x, y, z): 110 | self.x = x 111 | self._y = y 112 | self.__z = z 113 | 114 | pt = Point(10, 20, 30) 115 | print("pt.__dict__ = ", pt.__dict__) 116 | 117 | # Вывод 118 | # pt.__dict__ = {'x': 10, '_y': 20, '_Point__z': 30} 119 | ``` 120 | 121 | Мы назвали наш приватный атрибут как `__z` но в итоге видим как 122 | появился атрибут `_Point__z` и уже вызвав этот атрибут мы можем 123 | получить к нему доступ, даже несмотря на то, что он приватный. 124 | 125 | ```python 126 | print("pt._Point__z = ", pt._Point__z) 127 | 128 | # Вывод 129 | # pt._Point__z = 30 130 | ``` 131 | 132 | Таким образом мы можем получать доступ к приватным атрибутам обьекта. 133 | 134 | --- 135 | 136 | Модификатор доступа `protected` 137 | --- 138 | 139 | Создается при помощи одного нижнего подчеркивания, и говорит 140 | программисту, что этот атрибут следует использовать только внутри 141 | класса, или его дочерних классах, но по факту это никак не ограничивает 142 | доступ к атрибуту, и обращаться к нему можно из вне. 143 | 144 | Данный модификатор просто декоративный. 145 | -------------------------------------------------------------------------------- /Theory/Part_7/Function_all_any.md: -------------------------------------------------------------------------------- 1 | Функции` all()` и `any()` 2 | --- 3 | 4 | `all()` вернет `True` когда все члены полученной последовательности 5 | имеют `True`. 6 | 7 | `any()` вернет `True` когда хотя бы один из элементов полученной 8 | последовательности является `True` 9 | 10 | ```python 11 | print('all(1,1,0) = ', all([1,1,0])) 12 | print('all(1,1,1) = ', all([1,1,1])) 13 | print('any(1,0,1) = ', any([1,0,1])) 14 | print('any(0,0,0) = ', any([0,0,0])) 15 | 16 | # Вывод 17 | # all(1,1,0) = False 18 | # all(1,1,1) = True 19 | # any(1,0,1) = True 20 | # any(0,0,0) = False 21 | ``` -------------------------------------------------------------------------------- /Theory/Part_7/Iterators_expression_generators.md: -------------------------------------------------------------------------------- 1 | Итераторы, Выражения-генераторы 2 | --- 3 | Генератор - Это генератор, элементы которого можно перебирать только 4 | 1 раз. 5 | 6 | Итератор - Это обьект, который поддерживает функцию `next` для перехода 7 | к след элементу коллекции. 8 | 9 | Итерируемые обьекты - Это обьект, который позволяет поочередно обойти свои 10 | элементы и может быть преобразован к итератору. 11 | 12 | Для создания генератора можно использовать 2 способа: 13 | 14 | 1) Для этого можно использовать уже существующую последовательность, 15 | к примеру список, при помощи функции `iter()` создаем итерируемый обьект 16 | и при помощи функции `next()` проходимся по его элементам, каждый раз 17 | при вызове функции `next()` она будет вызывать следующий элемент 18 | итерируемого обьекта, и не может вернуться назад, при вызове большего 19 | количества чем содержится в итераторе раз, это даст ошибку: 20 | 21 | ```python 22 | lt1 = [1, 2, 3] 23 | 24 | it = iter(lt1) 25 | print(it) 26 | 27 | print(next(it)) 28 | print(next(it)) 29 | print(next(it)) 30 | 31 | # Вывод 32 | # 33 | # 1 34 | # 2 35 | # 3 36 | ``` 37 | 38 | 2) Второй способ это создать выражение-генератор, выглядит так же как и 39 | генерация списков, но с круглыми скобками, это создаст генератор, по 40 | которому можно будет пройтись уже без использования функции `next()` 41 | а просто вызывая его элементы последовательно: 42 | 43 | ```python 44 | lt2 = (element for element in range(1000)) 45 | 46 | for elem in lt2: 47 | print(elem) 48 | if elem >= 100: 49 | break 50 | 51 | for elem in lt2: 52 | print(elem) 53 | if elem >= 200: 54 | break 55 | ``` 56 | 57 | В качестве вывода увидим числа от 0 до 100 и от 100 до 200, если бы мы 58 | использовали списки то повторный вызов цикла вывел бы первые 100 59 | элементов повторно, но итераторы проходятся только 1 раз и не 60 | более того, так что вызов второго цикла приведет к выводу элементов 61 | с 100 до 200. 62 | 63 | Зачем нужны итераторы или выражения генераторы ? 64 | 65 | Дело в том что итераторы не хранят в памяти сразу все свои значения, а 66 | генерируют их по мере необходимости, при обращении к следующему элементу, 67 | так что така запись создания списка 68 | `my_list = [elem for elem in range(10000000000000)]` сожрет всю память, 69 | в то время как создание генератора такого типа 70 | `my_generator = (elem for elem in range(10000000000000))` 71 | Создаст генератор который, будет генерировать кожное новое значение при 72 | обращении к нему. -------------------------------------------------------------------------------- /Theory/Part_7/With.md: -------------------------------------------------------------------------------- 1 | Менеджеры контекста `with` 2 | --- 3 | --- 4 | При работе с некоторым ресурсом, в конце этот ресурс должен быть 5 | освобожден, при работе с исключениями мы делаем это в блоке 6 | `finally` этот блок выполнятся в любом случае, так открыв 7 | дескриптор файла его можно закрыть в финальном блоке. 8 | 9 | Это освобождение ресурса является настолько необходимым, что для 10 | него существует специальный отдельный синтаксис, так называемый 11 | менеджер контекста. 12 | 13 | `with` - получает ресурс и работает с ним под неким псевдонимом, 14 | и по завершению работы ресурс сам себя завершит. 15 | 16 | Пример работы исключения против менеджера контекста `with` : 17 | 18 | 1) Первый пример 19 | ```python 20 | # Пример открытия фалйа и его закрытие при помощи исключений 21 | try: 22 | file = open('file.txt', 'r') 23 | print("Пример с исключениями") 24 | for line in file: 25 | print(line) 26 | except Exception: 27 | raise 28 | finally: 29 | file.close() 30 | ``` 31 | 32 | 2) Второй пример 33 | ```python 34 | # Тот же пример но с менеджером контекста 35 | try: 36 | with open('file.txt', 'r') as file: 37 | print("Пример с менеджером контекста") 38 | for line in file: 39 | print(line) 40 | except Exception: 41 | raise 42 | ``` 43 | 44 | --- 45 | 46 | Создадим свой собственный менеджер контекста 47 | --- 48 | 49 | По сути менеджер контекста это класс который реализует 2 магических 50 | метода, `__enter__()` и `__exit__()`. 51 | 52 | `__enter__()` - метод что принимает входящее значение, в данном 53 | случае это `open('file.txt', 'r')` открытый на запись дескриптор 54 | файла, а возвращает этот метод то что попадет в псевдоним `as file` 55 | 56 | `__exit__()` - по завершению работы блока `with` вызывается метод 57 | `__exit__()` в котором можно закрыть дескриптор класса, и происходит 58 | это даже в том случае если в процессе работы возникло исключение. 59 | 60 | Функция выхода имеет свои аргументы def `__exit__(self, exc_type, exc_val, exc_tb):` 61 | где аргумент `exc_type` держит в себе все исключения которые могли 62 | возникнуть, или содержит `None` тут мы можем перехватить это исключение, 63 | если все шло по плану то исключений не будет, если ошибка возникла 64 | то тут мы его и увидим. 65 | 66 | В след примере мы создаем 2 вектора и с помощью оператора менеджер 67 | контекста складываем эти вектора вместе, случае если произошла 68 | ошибка мы отловим ее в `__exit__` и не будет сохранять новый 69 | высчитанный вектор, а если ошибки не было то мы сохраним вычисления. 70 | 71 | ```python 72 | class VectorTesting: 73 | 74 | def __init__(self, vector): 75 | self.__vector = vector 76 | 77 | def __enter__(self): 78 | self.temp = self.__vector[:] 79 | return self.temp 80 | 81 | # return False - обработка исключений передается на более 82 | # верхний уровень. True - будет уходить на ур выше. 83 | def __exit__(self, exc_type, exc_val, exc_tb): 84 | if exc_type is None: 85 | self.__vector[:] = self.temp 86 | return False 87 | 88 | # Пример работы с вектором 89 | vector_1 = [1, 2, 3] 90 | vector_2 = [5, 5, 5] 91 | print('vector_1 = ', vector_1) 92 | print('vector_2 = ', vector_2) 93 | 94 | # Складываем 2 вектора одинаковой длинны 95 | try: 96 | with VectorTesting(vector_1) as vector_temp: 97 | for i in range(len(vector_temp)): 98 | vector_temp[i] += vector_2[i] 99 | except Exception as e: 100 | print('Произошло исключение = ', e) 101 | 102 | print('Новый vector_1 = ', vector_1) 103 | ``` 104 | -------------------------------------------------------------------------------- /Theory/Part_7/Yield.md: -------------------------------------------------------------------------------- 1 | Функции-генераторы `yield` 2 | --- 3 | Используются для экономии занимаемой памяти, это по сути все те же самые 4 | итераторы, представим что у нас есть функция которая возвращает список 5 | из 100 элементов: 6 | 7 | ```python 8 | def get_number(): 9 | return list(range(100)) 10 | 11 | x = get_number() 12 | print(x.__sizeof__()) 13 | ``` 14 | 15 | Эта функция занимает 984 байт при том что формирует список из 100 чисел. 16 | 17 | При помощи спец оператора `yield` мы указываем какую переменную следует 18 | сделать значением итератора, которую этот итератор будет перебирать 19 | значения это переменной при каждой итерации методом `next()` 20 | 21 | ```python 22 | def get_yield_number(): 23 | for x in range(100): 24 | yield x 25 | print('Это никогда не будет выведено ') 26 | 27 | s = get_yield_number() 28 | 29 | print('Функция-генератор: ', s) 30 | print('Память функции-генератора: ', s.__sizeof__()) 31 | 32 | print(next(s)) 33 | print(next(s)) 34 | print(next(s)) 35 | ``` 36 | 37 | В функции мы создаем цикл в котором генерируем последовательность, и при 38 | помощи оператора `yield` указываем возвращаемое значение, именно это 39 | значение и будет возвращаться каждый раз когда мы будем вызывать 40 | следующую итерацию этой функции методом `next()` 41 | 42 | В результате вывода видим, что функция использующая оператор `yield` 43 | становится объектом генератором, и при помощи перебора методом `next()` 44 | мы можем вызвать все элементы последовательности из функции, и при 45 | всем этом благодаря тому что список не хранится в памяти, а генерирует 46 | значение при обращении к нему, занимаемая память будет всего 64 байта. 47 | 48 | Функция-генератор: .get_yield_number at 0x7f0605c4fdb0> 49 | Память функции-генератора: 64 50 | 0 51 | 1 52 | 2 53 | 3 54 | 55 | --- 56 | 57 | Что сделает след код ? 58 | --- 59 | 60 | Используя оператор `yield` мы создаем итерируемый объект, по которому 61 | можно пройтись только один раз, и итератор будет сдвигаться каждый раз 62 | при обращении к циклу, слово test будет выведено один раз, а далее 63 | при обращении каждый раз будет выводиться новое число. 64 | 65 | ```python 66 | def a(): 67 | print('test') 68 | for i in range(10): 69 | yield i 70 | 71 | for i in a(): 72 | print(i) 73 | 74 | # Вывод 75 | # test 76 | # 0 77 | # 1 78 | # 2 79 | # 3 80 | # 4 81 | # 5 82 | # 6 83 | # 7 84 | # 8 85 | # 9 86 | ``` -------------------------------------------------------------------------------- /Theory/Part_8/Copy_object.md: -------------------------------------------------------------------------------- 1 | Копирование обьектов 2 | --- 3 | --- 4 | **Модуль `copy.` Функции `copy.copy` и `copy.deepcopy`** 5 | 6 | Создать копию объекта можно при помощи 2 способов, использовать 7 | срез `[:]`, или метод `.copy()` методы работают по разному, но 8 | эффект от них одинаков, и по времени исполнения они действуют 9 | одинаково. 10 | 11 | Копирование может происходить 2 способами, при помощи обычного 12 | метода `obj.copy()` который есть у всех структур данных, так и 13 | при помощи спец модуля `copy` у которого есть спец метод 14 | `copy.copy(obj)` оба метода работают одинаково, их способ копирования 15 | называется `shallow copy` 16 | 17 | --- 18 | 19 | **2 метода копирования `shallow copy` и `deep copy`** 20 | 21 | Когда происходит обычное копирование структуры, то копирование 22 | происходит способом `shallow copy` этот метод копирует только 23 | верхний слой, то есть только самую первую вложенность, но если в 24 | структуре есть вложенная структура, то ссылка на нее остается 25 | старой. 26 | 27 | Вот пример: 28 | ```python 29 | import copy 30 | 31 | print('Использование обычного copy:') 32 | my_list_1 = [1, 2, 3, 4, 5, [1,2,3]] 33 | 34 | # my_list_2 = my_list_1.copy() 35 | my_list_2 = copy.copy(my_list_1) 36 | 37 | print('До изменения') 38 | print(f'my_list_1 : {my_list_1}') 39 | print(f'my_list_2 : {my_list_2}') 40 | 41 | print('\nИзменение') 42 | print('my_list_2[0] = 555') 43 | print('my_list_2[5][0] = 777\n') 44 | my_list_2[0] = 555 45 | my_list_2[5][0] = 777 46 | 47 | print('\nПосле изменения') 48 | print(f'my_list_1 : {my_list_1}') 49 | print(f'my_list_2 : {my_list_2}') 50 | 51 | # Вывод 52 | 53 | # Использование обычного copy: 54 | # До изменения 55 | # my_list_1 : [1, 2, 3, 4, 5, [1, 2, 3]] 56 | # my_list_2 : [1, 2, 3, 4, 5, [1, 2, 3]] 57 | 58 | # Изменение 59 | # my_list_2[0] = 555 60 | # my_list_2[5][0] = 777 61 | 62 | # После изменения 63 | # my_list_1 : [1, 2, 3, 4, 5, [777, 2, 3]] 64 | # my_list_2 : [555, 2, 3, 4, 5, [777, 2, 3]] 65 | ``` 66 | 67 | Как можно увидеть из примера, изменение верхнего слоя в новом списке 68 | не привел к изменению в другом списке, но изменение во вложенном 69 | списке, привело к изменению в обоих списках, то есть полностью 70 | скопирован только верхний слой, в то время как внутренний слой в 71 | обоих списках имеет одинаковую ссылку на один и тот же обьект. 72 | 73 | Чтобы сделать полную копию всех обьектов структуры со всей степенью 74 | вложенности, следует использовать метод `deepcopy` модуля `copy` 75 | 76 | --- 77 | 78 | **Модуль copy** 79 | 80 | Предоставляет 2 метода для копирования: 81 | 82 | 1) `copy.copy(obj)` - поверхностное копирование. 83 | 2) `copy.deepcopy(obj)` - глубокое рекурсивное копирование со всей степенью 84 | вложенности. -------------------------------------------------------------------------------- /Theory/Part_8/Ellipsis.md: -------------------------------------------------------------------------------- 1 | Ellipsis 2 | --- 3 | Это спец константа в питоне, состоит из трех многоточий `...` она имеет 4 | несколько применений: 5 | 6 | 1) Плейсхолдер как замена оператора `pass` 7 | 8 | ```python 9 | def func1(): 10 | print('Внутреняя функция func1') 11 | pass 12 | 13 | def func2(): 14 | print('Внутреняя функция func2') 15 | ... 16 | 17 | func1() 18 | func2() 19 | 20 | # Вывод 21 | # Внутреняя функция func1 22 | # Внутреняя функция func2 23 | ``` 24 | 25 | 2) Второй способ это отсутствие каких либо аргументов совсем, `None` 26 | это тоже аргумент. 27 | 28 | ```python 29 | def original_num(m=...): 30 | if m is ...: 31 | print('Было передано ...') 32 | if m is None: 33 | print('Было передано None') 34 | if instance(m, int) : 35 | print('Было передано int') 36 | 37 | original_num() 38 | 39 | # Вывод 40 | # print('Было передано ...') 41 | ``` -------------------------------------------------------------------------------- /Theory/Part_8/Function_enumerate.md: -------------------------------------------------------------------------------- 1 | ### Функция `enumerate` 2 | Что такое цикл `for` ? По сути своего механизма этот цикл работает 3 | с переданной в него последовательностью как с итератором, когда у 4 | нас есть последовательность и мы передаем ее в цикл, то сам цикл 5 | работает со ссылкой на индекс последовательности. 6 | 7 | Изменения этого значения не дает изменения значений в списке, заменяется 8 | лишь переменная в которой содержится ссылка: 9 | 10 | ```python 11 | ml_1 = [1, 2, 3, 4, 5] 12 | print(f'Список до : {ml_1}') 13 | 14 | for element in ml_1: 15 | element = '+' 16 | 17 | print(f'Список после : {ml_1}') 18 | 19 | Список до : [1, 2, 3, 4, 5] 20 | Список после : [1, 2, 3, 4, 5] 21 | ``` 22 | 23 | Для того чтобы получить доступ к самим значениям, требуется 24 | использовать доступ по индексу, это можно сделать так: 25 | 26 | ```python 27 | ml_2 = [1, 2, 3, 4, 5] 28 | print(f'Список до : {ml_2}') 29 | 30 | for iter in range(len(ml_2)): 31 | ml_2[iter] = '+' 32 | 33 | print(f'Список после : {ml_2}') 34 | 35 | Список до : [1, 2, 3, 4, 5] 36 | Список после : ['+', '+', '+', '+', '+'] 37 | ``` 38 | 39 | По сути тут мы генерируем последовательность, которая по своим 40 | значениям будет соответствовать индексам последовательности. 41 | 42 | Также можно использовать класс `enumerate()` который принимает 43 | последовательность, и возвращает кортеж из индекса и значения 44 | последовательности, и по этому индексу будем иметь доступ к списку, 45 | и можем менять его: 46 | 47 | ```python 48 | ml_3 = [1, 2, 3, 4, 5] 49 | print(f'Список до : {ml_3}') 50 | 51 | for iter, value in enumerate(ml_3): 52 | print(f'{iter} = {value} || ml_3[{iter}] = {ml_3[iter]}') 53 | 54 | print(f'Список после : {ml_3}') 55 | 56 | Список до : [1, 2, 3, 4, 5] 57 | 0 = 1 || ml_3[0] = 1 58 | 1 = 2 || ml_3[1] = 2 59 | 2 = 3 || ml_3[2] = 3 60 | 3 = 4 || ml_3[3] = 4 61 | 4 = 5 || ml_3[4] = 5 62 | Список после : [1, 2, 3, 4, 5] 63 | ``` -------------------------------------------------------------------------------- /Theory/Part_8/Get_information_about_memory.md: -------------------------------------------------------------------------------- 1 | Память в Python `__sizeof__()` `sys.getsizeof()` 2 | --- 3 | 4 | У каждого объекта в Python есть метод `__sizeof__()` этот метод 5 | показывает сколько памяти, затрачивает питон в байтах на содержание 6 | этого объекта, но этот метод выводит память самого объекта и только 7 | его самого, помимо этого метода есть метод модуля `sys.getsizeof()` 8 | который выводит и память объекта и дополнительно количество памяти 9 | которе сборщик мусора затрачивает на хранение количества ссылок на 10 | этот объект, и потому получается больше: 11 | 12 | ```python 13 | a = [1, 2, 3] 14 | print('sys.getsizeof(a) = ', sys.getsizeof(a)) 15 | print('a.__sizeof__() = ', a.__sizeof__()) 16 | 17 | # Вывод 18 | # sys.getsizeof(a) = 88 19 | # a.__sizeof__() = 64 20 | ``` 21 | 22 | Также есть и другая проблема, когда у нас есть некий обьект, 23 | чтобы получить от него обьем занимаемой им памяти, оба метода 24 | дадут лишь обьем памяти самого обьекта, но не обьектов вложенных 25 | в него, таким образом мы получаем не весь обьем памяти, что тратится 26 | на содержание обьектов. 27 | 28 | ```python 29 | a = [1, 2, [Point(10, 10), Point(10, 10), Point(10, 10)]] 30 | b = [1, 2, 3] 31 | 32 | # // Вывод для обоих обьектов 33 | 34 | # sys.getsizeof(obj) = 88 35 | # obj.__sizeof__() = 64 36 | 37 | # sys.getsizeof(obj) = 88 38 | # obj.__sizeof__() = 64 39 | ``` 40 | 41 | У нас есть 2 списка, применение обоих методов даст один и тот же 42 | результат, память только самого списка, f не его вложенных объектов, 43 | обы получить всю память затрачиваемую на хранение со всей вложенностью, 44 | используется модуль`pympler` 45 | 46 | ### Модуль `pympler` 47 | Этот модуль используется для дебага и трекинга, его подмодуль `asizeof` 48 | имеет одноименный метод `asizeof()` который возвращает всю память, 49 | что тратится на хранение всех объектов со всей вложенностью. 50 | 51 | ```python 52 | from pympler import asizeof 53 | 54 | a = [1, 2, [Point(10, 10), Point(10, 10), Point(10, 10)]] 55 | b = [1, 2, 3] 56 | 57 | asizeof.asizeof(a) 58 | asizeof.asizeof(b) 59 | 60 | # Вывод в байтах 61 | # a = 184 62 | # b = 888 63 | ``` -------------------------------------------------------------------------------- /Theory/Part_8/Hash.md: -------------------------------------------------------------------------------- 1 | Хэширование в программировании 2 | --- 3 | --- 4 | Современный алгоритм хеширования называется `SHA-3` он существует 5 | с 2015 года. 6 | 7 | Криптографическая хеш-функция - это алгоритм, который преобразует 8 | произвольные данные в целые числа. 9 | 10 | --- 11 | 12 | Функция `hash()` 13 | --- 14 | По сути хеширование - это алгоритм, что вычисляет целое число для 15 | данных, в случае хеширования самих целых чисел, получим само это 16 | число, но для всех остальных типов данных будет вычислено новое число. 17 | 18 | Для целых чисел и чисел с плавающей точкой хеш значение вычисляется 19 | всегда одно и тоже. 20 | 21 | Хеширование используется только для неизменяемых типов данных, то есть 22 | мы не можем использовать `hash()` функцию для списков словарей и 23 | множеств. 24 | 25 | Кортежи являются неизменяемыми типами данных, но сами кортежи могут 26 | содержать в себе изменяемые типы, в случае если кортеж содержит только 27 | не изменяемые данные то его можно использовать для хеширования, то 28 | есть если он содержит числа и строки то да, а если в нем появляется 29 | список то уже нет. 30 | 31 | ```python 32 | my_set1 = (1,2,'sfd') 33 | hash1 = hash(my_set1) 34 | 35 | print(my_set1) 36 | print(hash1) 37 | 38 | my_set2 = (1,2, [1,2,3]) 39 | hash2 = hash(my_set2) 40 | 41 | print(my_set2) 42 | print(hash2) 43 | 44 | # Будет ошибка 45 | ``` -------------------------------------------------------------------------------- /Theory/Part_8/Module.md: -------------------------------------------------------------------------------- 1 | Создание Модулей 2 | --- 3 | --- 4 | -------------------------------------------------------------------------------- /Theory/Part_8/Unpacking.md: -------------------------------------------------------------------------------- 1 | Расширенная распаковка 2 | --- 3 | --- 4 | 5 | Распаковка возможна не только для структур данных, но и для строк 6 | и для объекта `range()` 7 | 8 | ```python 9 | x, y, z = 'abs' 10 | print(x, y, z) 11 | 12 | a, *b = 10, (20, 30), (40, 50) 13 | print(a, b) 14 | 15 | x, y = b 16 | print(x, y) 17 | 18 | first, *second, last = range(1, 5) 19 | print(f'first = {first} second = {second} last = {last}') 20 | ``` 21 | 22 | Также интересен то как происходит присваивание, при этом процессе 23 | значения перезаписываются, к примеру так: 24 | 25 | ```python 26 | x, (x, y) = 1, (2, 3) 27 | 28 | print(x) 29 | print(y) 30 | 31 | # Вывод 32 | # 2 33 | # 3 34 | ``` 35 | 36 | С начала x получает значение 1, а после перезаписывается на 2, а 37 | y получает значение 3 38 | 39 | -------------------------------------------------------------------------------- /Theory/Part_8/Virtual.md: -------------------------------------------------------------------------------- 1 | Виртуальное окружение venv 2 | --- 3 | --- 4 | 5 | [Почитать подробно тут.](https://fixmypc.ru/post/sozdanie-virtualnogo-okruzheniia-v-python-3-s-venv-i-virtualenv/) 6 | 7 | Есть 2 способа работать с интерпретатором питона, можно запускать 8 | программу с использованием python из самой ОС в Linux, который 9 | находится по пути `/usr/bin/python` 10 | 11 | Второй способ заключается в создании локального python интерпретатора, 12 | прямо внутри самого проекта, скачивание и установка модулей прямо в 13 | этот проект. 14 | 15 | Установка в Ubuntu 16 | 17 | pip3 install --user virtualenv virtualenvwrapper 18 | 19 | Установка python3.8 для создания вирт-окружение 20 | 21 | sudo apt install python3.8-venv 22 | 23 | В самом созданном проекте создаем вирт-окружение с версией 3.8 24 | 25 | python3.8 -m venv venv 26 | 27 | Чтобы активировать виртуальное окружение в терминале, запускаем 28 | команду: 29 | 30 | source venv/bin/activate 31 | 32 | После этого в терминале будет дописано `(venv)` что означает что 33 | мы находимся в виртуальном окружении, и теперь все устанавливаемые 34 | библиотеки, пакеты, модули будут устанавливаться в директорию `venv` 35 | 36 | После активации можно посмотреть версию интерпретатора python 37 | что будет использована: 38 | 39 | python --version 40 | 41 | # Вывод 42 | Python 3.8.0 43 | 44 | Деактивация окружения: 45 | 46 | deactivate 47 | 48 | --- 49 | 50 | Установка зависимостей 51 | --- 52 | Когда мы находимся в вирт.окруж `venv` командой `pip freeze` 53 | можно вывести список всех установленных пакетов. 54 | 55 | ``` 56 | pip3 freeze 57 | 58 | absl-py==0.13.0 59 | asgiref==3.4.1 60 | astunparse==1.6.3 61 | cachetools==4.2.2 62 | certifi==2021.5.30 63 | ``` 64 | 65 | Следующим способом мы экспортируем этот список в файл 66 | Requirements.txt 67 | 68 | pip3 freeze > Requirements.txt 69 | 70 | На другом компьютере, когда другой человек скачает репозиторий, 71 | он может одной командой установить все перечисленные библиотеки 72 | с помощью одной команды. 73 | 74 | pip3 install -r Requirements.txt 75 | 76 | Так можно быстро устанавливать все зависимые библиотеки. 77 | 78 | --- 79 | Переменные окружения 80 | --- 81 | 82 | В ОС есть `Переменные окружения` специальные переменные для хранения служебной информации, 83 | с помощью python мы можем использовать их в своем проекте как настройки программы. 84 | 85 | Хорошей практикой принято считать создание в корне проекта файла `.env.template` который 86 | будет служить шаблоном переменных окружения для заполнения, в нем не будет данных, только 87 | указание названия какие переменные будут использоваться. 88 | 89 | Содержимое файла `.env.template` 90 | ``` 91 | # int 92 | VAR1= 93 | # str 94 | VAR2= 95 | # str, separate with , 96 | VAR3= 97 | # bool 98 | VAR4= 99 | ``` 100 | 101 | На основе шаблона будем заполнять наш боевой файл с переменными окружения`.env` 102 | ``` 103 | VAR1=55 104 | VAR2=hello world 105 | VAR3=A,B,C,D 106 | VAR4=True 107 | ``` 108 | 109 | Для получения переменных окружения в python есть специальный модуль 110 | 111 | pip install python-dotenv==0.21.0 112 | 113 | С его помощью можно получать переменные окружения, по дофолту он настроен на извлечения 114 | переменных из файла `.env` в текущей директории, хорошей практикой считается расположение 115 | файла `settings.py` который и будет извлекать все данные из переменных окружения, и 116 | импортируя который можно получать доступ ко всем настройкам. 117 | 118 | ```python 119 | from os import environ 120 | from dotenv import load_dotenv 121 | 122 | load_dotenv() 123 | 124 | """int""" 125 | VAR1 = int(environ.get("VAR1", 55)) 126 | """str""" 127 | VAR2 = str(environ.get("VAR2", '')) 128 | """list""" 129 | VAR3 = str(environ.get("VAR3", 'A,B,C')).split(',') 130 | """bool""" 131 | VAR4 = bool(environ.get("VAR4", True)) 132 | ``` 133 | -------------------------------------------------------------------------------- /Theory/Part_8/pypi.md: -------------------------------------------------------------------------------- 1 | Публикация пакетов на PyPi 2 | --- 3 | --- 4 | 5 | Для выпуска проекта на https://pypi.org/, следует на нем 6 | зарегистрироваться. 7 | 8 | Все пакеты, что устанавливаются через `pip` или `pip3` хранятся на 9 | официальном сайте https://pypi.org/ там же можно выложить в открытый 10 | доступ и свои пакеты. 11 | 12 | Создаем свой пакет с модулями по следующей структуре, сам проект имеет 13 | название `ProjectName` в нем находится пакет с таким же названием, в 14 | котором хранятся все модули с файлом `__init__.py` на верхнем уровне 15 | находятся еще 2 файла, `setup.py` и `LICENSE` 16 | ``` 17 | ProjectName / 18 | | 19 | ----> ProjectName/ 20 | | ----> __init__.py 21 | | ----> module_1.py 22 | | ----> module_2.py 23 | | 24 | ----> setup.py 25 | ----> LICENSE 26 | ----> README.md 27 | ``` 28 | 29 | --- 30 | 31 | Добавляем лицензию 32 | --- 33 | 34 | `LICENSE` - Создаем файл с лицензией распространения программы, 35 | выбираем `MIT License` со следующим содержанием, только заменяем 36 | `[YEAR]` и `[NAME]` на свои: 37 | 38 | ``` 39 | MIT License 40 | 41 | Copyright (c) [YEAR] [NAME] 42 | 43 | Permission is hereby granted, free of charge, to any person obtaining a copy 44 | of this software and associated documentation files (the "Software"), to deal 45 | in the Software without restriction, including without limitation the rights 46 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 47 | copies of the Software, and to permit persons to whom the Software is 48 | furnished to do so, subject to the following conditions: 49 | 50 | The above copyright notice and this permission notice shall be included in all 51 | copies or substantial portions of the Software. 52 | 53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 54 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 56 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 57 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 58 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 59 | SOFTWARE. 60 | ``` 61 | 62 | --- 63 | Модуль `setuptools` и файл с настройками `setup.py` 64 | --- 65 | 66 | Устанавливаем модуль `setuptools` 67 | ``` 68 | pip3 install setuptools 69 | ``` 70 | 71 | Создаем файл `setup.py` 72 | 73 | `setup.py` - специальный файл с настройками, для организации программы 74 | в проект для загрузки на PyPi и наполняем его содержимым, тут будут 75 | настройки для описания программы, которая будет выложена на PyPi 76 | 77 | ```python 78 | # Импортируем установленный setuptools 79 | import setuptools 80 | 81 | # Открываем файл README.md и получаем из него все описание, это описание 82 | # мы используем для титульной страницы проекта на сайте PyPi 83 | with open("README.md", "r") as fh: 84 | long_description = fh.read() 85 | 86 | # Устанавливаем настройки 87 | setuptools.setup( 88 | name="ComputMath", # Название проекта 89 | version="1.0.1", # Версия проекта 90 | author="Name", # Имя автора 91 | author_email="some@yandex.ru", # Ваша почта что зарег-на на pypi 92 | description="Computational Mathematics Package", # Краткое описание 93 | 94 | # Полное описание, тут мы используем описание из README.md иначе 95 | # можно тут описать его заново 96 | long_description=long_description, 97 | # Формат в котором будет восприниматься полное описание 98 | long_description_content_type="text/markdown", 99 | # адрес вашей программы на github 100 | url="https://github.com//", 101 | 102 | packages=setuptools.find_packages(), 103 | # Версия питона, лицензия распространения, ОС на которой будет работать 104 | classifiers=[ 105 | "Programming Language :: Python :: 3.8", 106 | "License :: OSI Approved :: MIT License", 107 | "Operating System :: Unix", 108 | ], 109 | # Зависимости 110 | python_requires='>=3.6', 111 | ) 112 | ``` 113 | 114 | --- 115 | 116 | Создание дистрибутивных файлов 117 | --- 118 | 119 | Сгенерируем дистрибутивные файлы, которые другие пользователи будут 120 | загружать и распаковывать, для этого нам потребуется еще один 121 | инструмент `wheel`: 122 | 123 | ``` 124 | pip3 install wheel 125 | ``` 126 | 127 | В каталоге, в котором находится файл `setup.py` выполним следующую 128 | команду, для генерации файлов загрузки: 129 | 130 | ``` 131 | python3 setup.py sdist bdist_wheel 132 | ``` 133 | 134 | Произойдет генерация дистрибутивных файлов: 135 | 136 | ``` 137 | build 138 | ProjectName.egg-info 139 | dist 140 | ``` 141 | 142 | --- 143 | Инструмент `twine` 144 | --- 145 | 146 | Установим инструмент `twine` для загрузки проекта на PyPi : 147 | 148 | ``` 149 | pip3 install twine 150 | ``` 151 | 152 | Сам ресурс PyPi предоставляет тестовую среду, для проверки загрузки, 153 | вот 2разные команды для загрузки на тест и прод: 154 | 155 | ``` 156 | # Загрузка на тест 157 | twine upload --repository testpypi dist/* 158 | 159 | # Загрузка на прод 160 | twine upload --repository pypi dist/* 161 | 162 | # Или такая команда 163 | twine upload dist/* 164 | ``` 165 | 166 | После этого потребуется ввести свои данные, для аккаунта на PyPi, 167 | после этого проект будет загружен. -------------------------------------------------------------------------------- /Theory/Part_9/Geo_data.md: -------------------------------------------------------------------------------- 1 | API для получения Гео-данных 2 | --- 3 | --- 4 | Существует несколько специальных сервисов для получения гео-данных 5 | по адресу или координатам долготы и широты. 6 | 7 | --- 8 | Yandex geocoder API 9 | --- 10 | Для работы требуется зарегистрировать почту на `Yandex`, после в 11 | разделе для разработчиков по адресу 12 | [Yandex Services](https://developer.tech.yandex.ru/services/) 13 | потребуется подключить сервис **JavaScript API и HTTP Геокодер** 14 | после процесса регистрации, будет сгенерирован ключ API 15 | 16 | Библиотека на PyPi 17 | 18 | https://pypi.org/project/yandex-geocoder/ 19 | 20 | Yandex geocoder API хорошо парсит адреса но дает только `1000` запросов 21 | в день, больше только платно. 22 | 23 | --- 24 | OSM OpenStreetMap API 25 | --- 26 | 27 | Сам OSM это открытый API, не требует регистрации и секретных ключей. 28 | 29 | Для работы с ним можно использовать библиотеку `geocoder` которую 30 | можно найти на [PyPi](https://pypi.org/project/geocoder/) 31 | 32 | ```python 33 | import geocoder 34 | 35 | geo = geocoder.osm('Адресс тут') 36 | 37 | print('lat = ', geo.json['lat']) 38 | print('lng = ', geo.json['lng']) 39 | ``` 40 | 41 | OSM позволяет делать сколь угодно много запросов, но плохо парсит адреса. 42 | 43 | --- 44 | DaData API 45 | --- 46 | Сервис [DaData](https://dadata.ru/) дает услуги по геокодированию, 47 | и многое другое, для работы потребуется регистрация, предоставляет 48 | 2 секретных ключа, для работы потребуются оба. 49 | 50 | Установка модуля для работы с [DaData](https://github.com/hflabs/dadata-py) 51 | 52 | ример работы с сервисом 53 | ```python 54 | from dadata import Dadata 55 | 56 | api_key = "api ключ" 57 | secret_key = "секретный ключ" 58 | 59 | dadata = Dadata(api_key, secret_key) 60 | result = dadata.clean(name="address", source="москва сухонская 11") 61 | 62 | print('lat = ', result['geo_lat']) 63 | print('lng = ', result['geo_lon']) 64 | ``` 65 | 66 | Позволяет использовать `10 000` бесплатных запросов в день, под ккапотом 67 | использует тот же сервис OSM, но берет на себя нагрузу по парсингу адреса 68 | из строки, определяет адреса так же хорошо как и `Yandex geocoder API` 69 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_CSV.md: -------------------------------------------------------------------------------- 1 | Модуль `CSV` 2 | --- 3 | --- 4 | Формат CSV используют, чтобы хранить таблицы в текстовых файлах. 5 | Данные очень часто упаковывают именно в таблицы, поэтому CSV-файлы 6 | очень популярны, он хорошо подходит для работы в Excel файлах, если 7 | его правильно импортировать, чтобы не запороть данные. 8 | 9 | CSV расшифровывается как comma-separated values — «значения, 10 | разделенные запятыми», однако на самом деле в качестве разделителя 11 | можно использовать и символы табуляции. 12 | 13 | Пример csv файла: 14 | ``` 15 | full_name;salare;kpi 16 | Ivanov Alex;100000;5 17 | Smirnov Alex;120000;7 18 | Andreev Vadim;110000;4 19 | Petrova Ira;90000;3 20 | ``` 21 | Этот файл при открытии в Excel примет следующий вид: 22 | 23 | | full_name | salare | kpi | 24 | | ------------- |:-------:| ---:| 25 | | Ivanov Alex | 100000 | 5 | 26 | | Smirnov Alex | 120000 | 7 | 27 | | Andreev Vadim | 110000 | 4 | 28 | | Petrova Ira | 90000 | 3 | 29 | 30 | Первая строка всегда задает столбцы, а все последующие это 31 | строки таблицы. 32 | --- 33 | Проблема при открытии в Excel 34 | --- 35 | 36 | Есть проблемы, при работе с csv через Excel, если в файле есть 37 | данные типа `5235834,5235835` что является строкой с 2 номерами 38 | через запятую, то Excel преобразует это к виду числа, округлив 39 | второе число, и мы получим `5235834,52` 40 | 41 | Приводит к экспоненциальной форме. Excel заботливо 42 | преобразует `«123456789012345»` в число `«1,2E+15»` 43 | 44 | Удаляет лидирующие плюсы `«+74955235834»` в формат `«74955235834»` 45 | 46 | Удаляет лидирующие нули, строку `«00523446»` Excel превратит в 47 | `«523446»` 48 | 49 | Чтобы изменить это все, требуется поменять тип импорта данных, 50 | по умолчанию Excel применяет к данным в загруженном CSV-файле 51 | тип «General» — общий. 52 | 53 | Запускаю встроенный в Excel механизм импорта. В меню это 54 | `«Data → Get External Data → From Text»` 55 | --- 56 | Модуль csv позволяет как читать, так и создавать файлы этого 57 | формата. 58 | 59 | Существует два способа чтения файлов CSV, использовать функцию 60 | чтения модуля csv, или использовать класс DictReader, используем 61 | оба способа. 62 | 63 | Первый способ позволяет работать с каждой строкой как со списком, 64 | второй метод взаимодействует с каждой строчкой файла как со 65 | словарем, где в качестве ключа используется название столбца. 66 | 67 | ```python 68 | import csv 69 | 70 | # Путь к файлу CSV 71 | csv_path = "csv-1/exp-1.csv" 72 | 73 | # Используем менеджер контекста чтобы быть уверенными что 74 | # дескриптор файла будет закрыт 75 | with open(csv_path, 'r') as file_obj: 76 | reader = csv.reader(file_obj) 77 | for row in reader: 78 | print(" ".join(row)) 79 | ``` 80 | 81 | `csv.reader()` - Получить список со строчками файла. 82 | 83 | `csv.writer(csv_file, delimiter=';')` - записать списки в файл как 84 | строчки, с указанием какой разделитель использовать. 85 | 86 | `csv.DictReader(file_obj, delimiter=',')` - получить словарь со 87 | строчками файла, и указанием какой разделитель в файле используется. 88 | 89 | Записать в файл список со словарями, где каждый словарь это строка, 90 | и сама запись в файл с использованием метода `writer.writerow()` 91 | ```python 92 | writer = csv.DictWriter(out_file, delimiter=';', fieldnames=fieldnames) 93 | writer.writerow(row) 94 | ``` -------------------------------------------------------------------------------- /Theory/Part_9/Module_crontab.md: -------------------------------------------------------------------------------- 1 | Планировщик `crone` и модуль `crontab` 2 | --- 3 | --- 4 | 5 | `cron` - Это системный планировщик, классический демон в системе 6 | UNIX используется для выполнения заданий в положенный момент времени, 7 | инструкции поменяются в файл crontab и находится в специальных 8 | каталогах. 9 | 10 | При запуске, сервис открывает главный файл `/etc/crontab` в котором 11 | планировщик запускает скрипты на запуск других cron файлов, именно 12 | он запускает файлы из следующих директорий: 13 | 14 | 1) `/etc/cron.d/` - для управления всей системой 15 | 2) `/etc/cron.minutely` - каждую минуту 16 | 3) `/etc/cron.hourly` - каждый час 17 | 4) `/etc/cron.daily/` - файлы выполняются в день 18 | 5) `/etc/cron.weekly/` - в неделю 19 | 6) `/etc/cron.monthly/` - в месяц 20 | 21 | `cron` имеет специальный синтаксис для описания выполняемых заданий. 22 | 23 | --- 24 | 25 | **Переменные оболочки** 26 | 27 | Во-первых, в каждом файле переопределяются переменные оболочки, 28 | `SHELL` - указывает путь к интерпретатору, `PATH` - переопределяет пути, 29 | где оболочка будет искать файлы со скриптами для исполнения. 30 | `MAILTO` - указывает почту куда отправить результат о выполнение 31 | скрипта, помимо этого можно указать файл для вывода. 32 | 33 | SHELL=/bin/sh 34 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 35 | MAILTO=qwerty@yandex.ru 36 | 37 | **Сам скрипт cron** 38 | 39 | С начала указывается время выполнения, далее пользователь от лица 40 | которого будет выполнена работа, и сам скрипт. 41 | 42 | Minute Hour Day Month Day_of_the_Week User Script 43 | 17 * * * * root cd / && run-parts --report /etc/cron.hourly 44 | --- 45 | 46 | `cron` файлы для конкретного пользователя. 47 | --- 48 | Помимо системного cron, можно создавать cron задания для конкретного 49 | пользователя Linux, для этого можно использовать след команды. 50 | 51 | Это покажет какие задания запущены для конкретного текущего пользователя: 52 | 53 | crontab -l 54 | 55 | Чтобы отредактировать эти команды след исп-ть команду: 56 | 57 | crontab -e 58 | 59 | Файл с cron командами будет назван по имени пользователя, и помещен в 60 | директорию: 61 | 62 | # Если имя пользователя "serg" 63 | /var/spool/cron/serg 64 | 65 | Команды будут работать с файловой системой в директории пользователя. 66 | 67 | К примеру такая команда будет выполняться каждую минуту, она запускает 68 | при помощи интерпретатора python файл `hello.py` который будет находиться 69 | в `/home/serg/hello.py` а результат вывода будет перенаправлен в 70 | файл по пути `/home/serg/a.txt` 71 | 72 | */1 * * * * python hello.py >> a.txt 73 | 74 | --- 75 | 76 | Роли и пользователи. 77 | 78 | cat /etc/passwd 79 | 80 | serg:x:1000:1000:serg,,,:/home/serg:/bin/bash 81 | redis:x:122:127::/var/lib/redis:/usr/sbin/nologin 82 | sshd:x:123:65534::/run/sshd:/usr/sbin/nologin 83 | mysql:x:124:128:MySQL Server,,,:/nonexistent:/bin/false 84 | postgres:x:125:129:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash 85 | 86 | --- 87 | 88 | Модуль питона `crontab` для создания `cron` команд 89 | --- 90 | 91 | Это модуль для создания запуска и изменения cron команд в Linux. 92 | 93 | https://pythobyte.com/scheduling-jobs-with-python-crontab-dd7c1635/ 94 | 95 | pip3 install python-crontab 96 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_functools.md: -------------------------------------------------------------------------------- 1 | Модуль `functools` 2 | --- 3 | --- 4 | 1) `@functools.lru_cache` - Пример использования функции мемоизатора, 5 | также для этой функции будет доступен новый метод `.cache_info()` 6 | для вывода содержимого кеша. 7 | 8 | ```python 9 | import functools 10 | 11 | @functools.lru_cache(maxsize=128) 12 | def function(a, b): 13 | return a * b 14 | 15 | print(function(2, 5)) 16 | print(function.cache_info()) 17 | 18 | print(function(20, 50)) 19 | print(function.cache_info()) 20 | 21 | # Вывод 22 | 23 | # 10 24 | # CacheInfo(hits=0, misses=1, maxsize=128, currsize=1) 25 | 26 | # 1000 27 | # CacheInfo(hits=0, misses=2, maxsize=128, currsize=2) 28 | ``` 29 | --- 30 | 31 | Декораторы и `functools`, `wraps()`, `update_wrapper()` 32 | --- 33 | Интересная вещь! Когда мы создаем декораторы, то у оборачиваемой 34 | функции есть свой набор атрибутов, такие как: `__doc__` `__name__` 35 | `__module__` 36 | 37 | Эти атрибуты заменяются на содержимое функции обертки, и это не 38 | хорошо, это можно изменить присвоив этим атрибутам данные 39 | оборачиваемой функции, вот пример: 40 | 41 | ```python 42 | def trace(function): 43 | def inner(*args, **kwargs): 44 | print('Название:{} Аргументы: {} {}'.format(function.__name__, args, kwargs)) 45 | return function(*args, **kwargs) 46 | inner.__doc__ = function.__doc__ 47 | inner.__name__ = function.__name__ 48 | inner.__module__ = function.__module__ 49 | return inner 50 | 51 | @trace 52 | def foo(x): 53 | """I am do anything useful""" 54 | return x 55 | 56 | print(foo(48)) 57 | print('foo.__doc__ = ', foo.__doc__) 58 | print('foo.__name__ = ', foo.__name__) 59 | print('foo.__module__ = ', foo.__module__) 60 | 61 | # Вывод 62 | # 48 63 | # foo.__doc__ = I am do anything useful 64 | # foo.__name__ = foo 65 | # foo.__module__ = __main__ 66 | ``` 67 | 68 | Таким образом мы сохраняем атрибуты и не выдаем внутреннее содержимое 69 | нашего декоратора, это поведение можно реализовать самостоятельно 70 | как это было в примере, но это уже реализовано в `functools` 71 | 72 | Для этого есть целых 2 метода: 73 | 74 | 1) `@functools.wraps(function)` - реализация через декоратор. 75 | 76 | 77 | 2) `functools.update_wrapper(inner, function)` - реализация просто 78 | через функцию. 79 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_moviepy.md: -------------------------------------------------------------------------------- 1 | Модуль `moviepy` 2 | --- 3 | --- 4 | 5 | Это библиотека Python для редактирования видео: вырезание, 6 | объединение, вставка заголовков, обработка видео и создание 7 | пользовательских эффектов, может читать и записывать все 8 | наиболее распространенные аудио и видео форматы, включая GIF. 9 | 10 | Установка: 11 | 12 | pip3 install moviepy 13 | 14 | Пример использования, скажем требуется форматировать видео из 15 | формата .mp4 в формат .mp3, скрипт берет файл mp4 в той же директории 16 | в которой лежит и сам скрипт, и форматирует в mp3 в ту же 17 | директорию. 18 | 19 | ```python 20 | from moviepy.editor import * 21 | import os 22 | 23 | # 24 | video = VideoFileClip(os.path.join( 25 | os.curdir, # откуда 26 | os.curdir, # куда 27 | "Sunless Sea - 11 Khans Heart.mp4") # название файла 28 | ) 29 | video.audio.write_audiofile(os.path.join( 30 | os.curdir, # откуда 31 | os.curdir, # куда 32 | "new_music.mp3") # новое название файла 33 | ) 34 | ``` -------------------------------------------------------------------------------- /Theory/Part_9/Module_os_1.md: -------------------------------------------------------------------------------- 1 | Модуль os 2 | --- 3 | `os` - Это модуль для работы с операционной системой, работа 4 | с файловой структурой, директориями. 5 | 6 | 7 | --- 8 | Модуль `os.path()` 9 | --- 10 | `os.path.basename` - вернет названия файла в этом пути, последний 11 | файл: 12 | 13 | ```python 14 | print(os.path.basename(r'C:\Python27\Tools\pynche\ChipViewer.py')) 15 | 16 | # Вывод 17 | # ChipViewer.py 18 | ``` 19 | 20 | `os.path.dirname` - вернет все до последнего файла: 21 | 22 | ```python 23 | print( os.path.dirname(r'C:\Python27\Tools\pynche\ChipViewer.py') ) 24 | 25 | # Вывод 26 | # C:\\Python27\\Tools\\pynche 27 | ``` 28 | 29 | `os.path.exists` - говорит о существовании файла или нет. 30 | 31 | `os.path.isdir / os.path.isfile` - аналогичная проверка на 32 | существование. 33 | 34 | `os.path.join` - совмещает пути при помощи разделителя в 35 | текущей операционной системе: 36 | 37 | ```python 38 | print(os.path.join(r'C:\Python27\Tools\pynche', 'ChipViewer.py')) 39 | 40 | # Вывод 41 | # C:\\Python27\\Tools\\pynche\\ChipViewer.py 42 | ``` 43 | --- 44 | 45 | Метод `os.walk(dir)` 46 | --- 47 | Этот метод получает аргумент, строку пути, сканирует все содержимое, и 48 | возвращает объект генератор со всем содержимым, содержимое генератора 49 | имеет структуру: 50 | 51 | ('Корень директории', [Список со всеми под директориями], [список файлов]) 52 | 53 | Пройдемся по генератору циклом for: 54 | 55 | 56 | ```python 57 | test_dir = 'test-dir' 58 | gener = os.walk(test_dir) 59 | 60 | for root, dirs, files in gener: 61 | print(root, dirs, files) 62 | 63 | # Вывод 64 | # test-dir ['test-dir-2'] ['test.txt'] 65 | # test-dir/test-dir-2 [] ['test-2.txt'] 66 | ``` 67 | Или методом `next()`: 68 | 69 | ```python 70 | test_dir = 'test-dir' 71 | gener = os.walk(test_dir) 72 | 73 | print(next(gener)) 74 | print(next(gener)) 75 | 76 | # Вывод 77 | # ('test-dir', ['test-dir-2'], ['test.txt']) 78 | # ('test-dir/test-dir-2', [], ['test-2.txt']) 79 | ``` 80 | Если использовать символ `/` то получим списки всех путей со всеми 81 | файлами во всей системе, это займет много времени, и заняло бы много 82 | памяти, если это была бы обычная структура, но это генератор и по 83 | этому он ест меньше памяти. 84 | 85 | --- 86 | 87 | `os.getcwd()` - Показать путь до текущей директории в которой 88 | запущен файл. 89 | 90 | --- 91 | 92 | `os.pardir` 93 | 94 | --- 95 | 96 | `os.listdir` - Она показывает все содержимое каталога, если команда 97 | `os.walk()` возвращает все содержимое до дна рекурсивно, то данная 98 | команда выводит список только одной директории. 99 | 100 | --- 101 | 102 | Удалить файл можно 2 способами 103 | --- 104 | 105 | 1) `os.remove('try.py')` 106 | 107 | 2) `os.unlink('try.py')` 108 | 109 | --- 110 | 111 | Получить директорию текущего пользователя 112 | --- 113 | Сделать это можно 2 путями: 114 | 115 | ```python 116 | os.getenv('HOME') 117 | os.path.expanduser('~') 118 | 119 | # Вывод для обычного пользователя: 120 | # /home/serg 121 | # /home/serg 122 | 123 | # Если речь идет о суперпользователе, то вывод будет таким: 124 | # /root 125 | ``` 126 | 127 | --- 128 | `os.fork()` - ??? 129 | 130 | --- 131 | `os.system("shutdown -s")` - Выключение компьютера. 132 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_os_2.md: -------------------------------------------------------------------------------- 1 | Модуль os 2 | --- 3 | --- 4 | 5 | os.name 6 | --- 7 | 8 | `os.name` - выводит платформу на которой происходит запуск 9 | программы, есть 2 основных: 10 | 11 | 1) `posix` - работа под одной из операционных систем UNIX 12 | 2) `nt` - работа под Windows 13 | 14 | --- 15 | 16 | Переменные окружения 17 | --- 18 | **os.environ, os.getenv() и os.putenv()** 19 | 20 | `os.environ` - это словарь в котором содержатся все переменые 21 | окружения, по сути ее вывод эквивалентен выводу команды 22 | `printenv` в оболочке `bash` 23 | 24 | Обратиться к ним можно как к словарю 25 | 26 | ```python 27 | for element in os.environ: 28 | print(f'{element} = {os.environ[element]}') 29 | ``` 30 | --- 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_pathlib.md: -------------------------------------------------------------------------------- 1 | Модуль pathlib 2 | --- 3 | 4 | [//]: # (https://docs.python.org/3/library/pathlib.html) 5 | 6 | С помощью стандартной библиотеки `os.path` можно управлять путями, но этот 7 | модуль неудобен в использовании, гораздо удобнее использовать модул `pathlib` 8 | 9 | Методы: 10 | 11 | - `Path.cwd()` - Получить текущую директорию, в которой запущен скрипт 12 | - `Path.home()` - Получить домашнюю директорию 13 | - `Path.is_dir()` - Проверка директории на существование 14 | - `Path.rmdir()` - Удаление директории 15 | - `Path.glob(pattern)` - Получить файлы по паттерну 16 | - `Path.mkdir()` - Создает директорию 17 | - `Path.rename()` - Переименует файл или директорию 18 | - `Path.rmdir()` - Удаляет директорию 19 | - `Path.unlink()` - Удаляет файл 20 | - `Path.open()` - Открывает файл 21 | - `Path.with_suffix('.txt')` - Возвращает путь полный путь, с другим суффиксом 22 | 23 | Получение информации о путях: 24 | 25 | - `path.parts` - Кортеж из частей пути до нужного файла 26 | - `path.name` - Возвращает название файла с расширением `file.txt` 27 | - `path.parent` - Весть путь до родительской директории 28 | - `path.stem` - Возвращает название файла без расширения `file` 29 | - `path.suffix` - Возвращает расширение файла `.md` `.txt` `.py` 30 | - `path.anchor` - Разделитель который используется в данной ОС 31 | - `path.match` - Проверяет, совпадает ли название файла с переданным паттерном 32 | 33 | --- 34 | Добавлять пути, переходить в директории, и обращаться к нужным файлам, 35 | можно удобным способом, через указание символа `/`, все создаваемые 36 | пути будут кроссплатформенны, как если бы мы использовали `os.path.join()` 37 | 38 | Находим файл с именем `workdir/file.txt` относительно текущего пути. 39 | ```python 40 | from pathlib import Path 41 | 42 | outpath = Path.cwd() / 'workdir' / 'file.txt' 43 | ``` 44 | 45 | --- 46 | Удобное совмещение контекста временной директории и удобной работы с 47 | путями `pathlib`: 48 | 49 | ```python 50 | from pathlib import Path 51 | import tempfile 52 | 53 | with tempfile.TemporaryDirectory(prefix='tmp_') as work_dir: 54 | workdir = Path(work_dir) 55 | ``` 56 | В данном примере, когда нам требуется манипулировать временными данными, 57 | мы можем использовать контекст `tempfile`, и удобную работу с путями от 58 | `pathlib`, удобная и красивая комбинация. 59 | 60 | --- 61 | 62 | `Path.with_suffix()` - Метод принимает суффикс, если суффикс у пути уже существует, 63 | то заменяет его, если суффикса не существовало, то добавляет его, если в качестве 64 | суффикса передана пустая строка, то удаляет уже существующий суффикс у пути. 65 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_prettytable.md: -------------------------------------------------------------------------------- 1 | Модуль `prettytable` 2 | --- 3 | --- 4 | Данный модуль создает красивые таблицы в терминале. 5 | 6 | Установка: 7 | 8 | pip3 install prettytable 9 | 10 | Использование: 11 | 12 | ```python 13 | from prettytable import PrettyTable 14 | 15 | # Создаем экземпляр таблицы 16 | table = PrettyTable() 17 | 18 | # Задаем колонки 19 | table.field_names = ['Names', 'Age', 'City'] 20 | 21 | # Создаем строчки 22 | table.add_row(["Алекс", 20, "Москва"]) 23 | table.add_row(["Боб", 25, "Москва"]) 24 | table.add_row(["Саша", 30, "Минск"]) 25 | table.add_row(["Петя", 23, "Киев"]) 26 | table.add_row(["Вася", 67, "Москва"]) 27 | 28 | # Выравнивание по краю 29 | table.align = 'l' 30 | 31 | # Сортировка схожая с ORDER BY в SQL 32 | table.sortby = "Age" 33 | 34 | # Вывод на экран 35 | print(table) 36 | 37 | # Вывод таблицы в терминале 38 | # 39 | # +-------+-----+--------+ 40 | # | Names | Age | City | 41 | # +-------+-----+--------+ 42 | # | Алекс | 20 | Москва | 43 | # | Петя | 23 | Киев | 44 | # | Боб | 25 | Москва | 45 | # | Саша | 30 | Минск | 46 | # | Вася | 67 | Москва | 47 | # +-------+-----+--------+ 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_pyperclip.md: -------------------------------------------------------------------------------- 1 | Модуль `pyperclip` 2 | --- 3 | --- 4 | 5 | `pyperclip` - управляет буфером обмена, теми данными что 6 | сохраняются в момент копирования `Ctrl+C` 7 | 8 | Данный модуль предназначен для работы со строчками, если 9 | в буфер обмен будет скопирован файл, то `pyperclip` вернет 10 | полный путь к этому файлу от корня файловой системы. 11 | 12 | Для установки, потребуется установить ряд 13 | дополнительных пакетов. 14 | 15 | sudo apt-get install xsel 16 | sudo apt-get install xclip 17 | pip3 install gtk 18 | pip3 install pyperclip 19 | 20 | Имеется 2 метода: 21 | 22 | 1) `paste()` - получает данные из буфера. 23 | 2) `copy()` - вносит данные в буфер. 24 | 25 | Пример использования, при условии, что перед запуском мы 26 | скопировали файл по пути `/var/www/python-script/main.py` 27 | 28 | ```python 29 | import pyperclip 30 | 31 | buffer_data = pyperclip.paste() 32 | 33 | print('pyperclip.paste() = ', buffer_data) 34 | 35 | print('С помощью метода pyperclip.copy() вносим данные') 36 | 37 | buffer_data = "Эти данные внесены в Буфер обмена." 38 | 39 | pyperclip.copy(buffer_data) 40 | 41 | # Вывод 42 | # pyperclip.paste() = /var/www/python-script/main.py 43 | # С помощью метода pyperclip.copy() вносим данные 44 | ``` -------------------------------------------------------------------------------- /Theory/Part_9/Module_pyshorteners.md: -------------------------------------------------------------------------------- 1 | Модуль `pyshorteners` 2 | --- 3 | --- 4 | 5 | `pyshorteners` - модуль создает короткие ссылки на ресурс. 6 | 7 | Установка : 8 | 9 | pip3 install pyshorteners 10 | 11 | Пример : 12 | ```python 13 | import pyshorteners 14 | 15 | # Создали обьет 16 | pyshort = pyshorteners.Shortener() 17 | 18 | # Полная сылка и коротка 19 | full_url = 'https://www.youtube.com/watch?v=pbMLW0nRvZY&list=RDMMpbMLW0nRvZY&start_radio=1' 20 | short_url = pyshort.tinyurl.short(full_url) 21 | 22 | print('Полная ссылка = ', full_url) 23 | print("Сокращенная ссылка - ", short_url) 24 | 25 | # Вывод 26 | # Полная ссылка = https://www.youtube.com/watch?v=pbMLW0nRvZY&list=RDMMpbMLW0nRvZY&start_radio=1 27 | # Сокращенная ссылка - https://tinyurl.com/yjzz49rt 28 | ``` -------------------------------------------------------------------------------- /Theory/Part_9/Module_random.md: -------------------------------------------------------------------------------- 1 | Модуль random 2 | --- 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_re.md: -------------------------------------------------------------------------------- 1 | Регулярные выражения 2 | --- 3 | --- 4 | 5 | Модуль `re` и его методы по поиску в тексте, написан на языке C что 6 | делает его очень быстрым. 7 | 8 | Импортируем модуль для регулярных выражений: 9 | 10 | import re 11 | 12 | Найти слово можно так `"map"` но в таком случае будут извлечены даже те 13 | слова что выглядят так `"bitmap"` для того чтобы найти именно отдельно 14 | стоящие слова, можно использовать такие способы: 15 | 16 | `" map "` - Найдет отдельно стоящее слово 17 | 18 | `"\\bmap\\b"` - Обрамив искомое слово символами `\\b` с двух сторон, мы 19 | указываем что должны найти именно отдельно стоящее слово. Здесь два 20 | слеша нужны для экранирования. 21 | 22 | `r"\bmap\b"` - Поставив указатель r перед строчкой, мы указываем что 23 | эта строка будет использована как регулярное выражение, и внутри 24 | можно уже не экранировать при помощи 2 слешей, а писать только так `\b` 25 | 26 | --- 27 | 28 | Специальные символы 29 | --- 30 | 31 | В регулярных выражениях есть спец символы, эти символы используются 32 | для функционала, вот они `\.^$&+*{}[]()` 33 | 34 | 35 | --- 36 | 37 | Метод `findall` 38 | --- 39 | 40 | Метод находит все вхождения подстроки в строке. 41 | 42 | re.findall(search, text) 43 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_requests.md: -------------------------------------------------------------------------------- 1 | Модуль `requests` 2 | --- 3 | --- 4 | `requests` - модуль для работы с HTTP запросами, 5 | отправлять `GET` и `POST` запросы. 6 | 7 | Установка: 8 | 9 | pip3 install requests 10 | 11 | Если используем виртуальную среду: 12 | 13 | pipenv install requests 14 | 15 | Можно посмотреть на различные данные пришедшие с 16 | ответом, `encoding` - кодировка ответа, статус код 17 | `status_code` (200 / 400 ...), `cookies` можно 18 | посмотреть куки `cookies`, был ли редирект с того 19 | ресурса, на который делали запрос `is_redirect`, 20 | `elapsed` время прошедшее с момента отправки и 21 | получения ответа, `url` с которого пришел ответ, 22 | может отличиться за счет редиректа, 23 | 24 | ```python 25 | url = "http://xakep.ru" 26 | response = requests.get(url) 27 | 28 | print('encoding = ', response.encoding) 29 | print('status_code = ', response.status_code) 30 | print('cookies = ', response.cookies) 31 | print('is_redirect = ', response.is_redirect) 32 | print('elapsed = ', response.elapsed) 33 | print('url = ', response.url) 34 | print('history = ', response.history) 35 | 36 | # Вывод 37 | # encoding = UTF-8 38 | # status_code = 200 39 | # cookies = 40 | # is_redirect = False 41 | # elapsed = 0:00:00.573094 42 | # url = https://xakep.ru/ 43 | # history = [] 44 | ``` 45 | 46 | `headers` - Можно увидеть все заголовки пришедшие от 47 | сервера. 48 | 49 | ```python 50 | url = "http://xakep.ru" 51 | response = requests.get(url) 52 | 53 | print(response.headers) 54 | 55 | # Вывод 56 | # { 'Server': 'QRATOR', 57 | # 'Date': 'Fri, 16 Jul 2021 02:34:37 GMT', 58 | # 'Content-Type': 'text/html; charset=UTF-8', 59 | # 'Content-Length': '26772', 60 | # 'Connection': 'keep-alive', 61 | # 'Link': '; 62 | # ... 63 | # } 64 | ``` 65 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_socket.md: -------------------------------------------------------------------------------- 1 | Модуль `socket` 2 | --- 3 | --- 4 | Cокет — это интерфейс обмена данными между процессами. 5 | Существуют клиентские и серверные сокеты. Серверный 6 | сокет слушает определенный порт в ожидании подключения 7 | клиентов, а клиентский подключается к серверу. После 8 | того как было установлено соединение, начинается 9 | обмен данными. 10 | 11 | Данный пример принимает название сайта, и при помощи 12 | модуля `socket` сканирует какие из портов этого сайта 13 | активны. 14 | 15 | ```python 16 | import socket 17 | 18 | # Список портов для сканирования 19 | ports = [20, 21, 22, 23, 25, 42, 43, 53, 67, 69, 80, 110, 115, 123, 137, 138, 139, 143, 161, 179, 443, 445, 514, 515, 993, 995, 1080, 1194, 1433, 1702, 1723, 3128, 3268, 3306, 3389, 5432, 5060, 5900, 5938, 8080, 10000, 20000] 20 | host = input('Введи имя сайта без http/https или IP-адрес: ') 21 | print ("Ожидай, идет сканирование портов!") 22 | # В цикле перебираем порты из списка 23 | for port in ports: 24 | # Создаем сокет 25 | s = socket.socket() 26 | # Ставим тайм-аут в одну cекунду 27 | s.settimeout(1) 28 | # Ловим ошибки 29 | try: 30 | # Пробуем соединиться, хост и порт передаем как список 31 | s.connect((host, port)) 32 | # Если соединение вызвало ошибку 33 | except socket.error: 34 | # тогда ничего не делаем 35 | pass 36 | else: 37 | print(f"{host}: {port} порт активен") 38 | # Закрываем соединение 39 | s.close 40 | print ("Сканирование завершено!") 41 | 42 | # Вывод 43 | # Введи имя сайта без http/https или IP-адрес: xakep.ru 44 | # Ожидай, идет сканирование портов! 45 | # xakep.ru: 80 порт активен 46 | # xakep.ru: 443 порт активен 47 | # Сканирование завершено! 48 | ``` -------------------------------------------------------------------------------- /Theory/Part_9/Module_sys.md: -------------------------------------------------------------------------------- 1 | Модуль sys 2 | --- 3 | --- 4 | 5 | Параметр `sys.executable` 6 | --- 7 | Параметр `sys.executable` выводит полный путь к интерпретатору Python 8 | 9 | ```python 10 | import sys 11 | 12 | print('sys.executable = ', sys.executable) 13 | 14 | # Вывод 15 | 16 | # Через обынчный локальный интерпретатор 17 | # python3 2.py 18 | # sys.executable = /var/www/Python-programm/venv/bin/python3 19 | 20 | # Через сшибанг в начале файла 21 | # ./2.py 22 | # sys.executable = /usr/bin/python3 23 | ``` 24 | 25 | --- 26 | 27 | Метод `sys.exit()` 28 | --- 29 | Используется для выхода из программы, имеет необязательный атрибут 30 | в виде числа, где 0 это успешный выход, при его использовании вызывается 31 | исключение типа `SystemExit` которое можно перехватывать. 32 | 33 | [comment]: <> (`sys.getsizeof()`) 34 | 35 | [comment]: <> (Если требуется получить) 36 | 37 | [comment]: <> (параметры из терминала sys.argv[1] это массив с параметрами) -------------------------------------------------------------------------------- /Theory/Part_9/Module_time.md: -------------------------------------------------------------------------------- 1 | Модуль time 2 | --- 3 | 4 | Это модуль для контроля за временем, есть ряд функций которые подходят 5 | для измерения времени выполнения, такие как: 6 | 7 | ```python 8 | time.monotonic() 9 | time.perf_counter() 10 | time.process_time() 11 | time() 12 | ``` 13 | 14 | И их наносекундные версии: 15 | 16 | ```python 17 | time.monotonic_ns() 18 | time.perf_counter_ns() 19 | time.process_time_ns() 20 | ``` 21 | 22 | 1) `time.sleep(seconds)` - метод sleep() принимает число секунд на 23 | которое следует остановить время выполнения программы. 24 | 25 | 3) `time.perf_counter()` - это метод берет текущее время и сохраняет его, 26 | разница между 2 такими переменными покажет сколько времени прошло между 27 | их вызовами. 28 | 29 | ```python 30 | time_1 = time.perf_counter() 31 | time.sleep(1) 32 | time_2 = time.perf_counter() 33 | 34 | print(f'{time_1} - {time_2} = {time_2 - time_1}') 35 | 36 | # Вывод 37 | # 24128.187585572 - 24129.188658062 = 1.001072490002116 38 | ``` 39 | 40 | Видим что разница между вызовами составила чуть более 1 секунды. 41 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_weakref.md: -------------------------------------------------------------------------------- 1 | Слабые ссылки и модуль `weakref` 2 | --- 3 | --- 4 | В отличие от обычных ссылок не препятствуют сборщику мусора удалять 5 | объект, если на объект остаются сильные ссылки то он не будет 6 | удален, но если остается только слабая ссылка то сборщик мусора 7 | его пожрет. 8 | 9 | Главная сфера их применения это работа с кешами и работа с большими 10 | словарями содержащими большие объекты которые не должны долго 11 | задерживаться в памяти. 12 | 13 | Модуль `weakref` пользуется для работы со слабыми ссылками, 14 | 15 | weakref.WeakKeyDictionary() 16 | weakref.WeakValueDictionary 17 | finalize() - регистрирует функцию очистки 18 | 19 | Для того чтобы обьект поддерживал слабые ссылки ему требуется хранить 20 | в себе некоторые указатель, это требует памяти, встроенные обьекты не 21 | всегда имеют такую выделенную память для поддержки слабых ссылок, у 22 | каждого обьекта в Python, атрибут `__weakrefoffset__` который говорит 23 | сколько памяти у обьекта выделено для поддержки слабых ссылок. 24 | 25 | `__weakrefoffset__` - возвращает число байтов указывающее сколько памяти 26 | обьект выделяет для поддержки слабых ссылок, если возвращает ноль то 27 | значит не поддерживает. Собственные классы, определенные самим 28 | пользователем, имеют стандартные 24 байта. 29 | 30 | ```python 31 | class Function: 32 | pass 33 | 34 | print('Function.__weakrefoffset__ = ', Function.__weakrefoffset__) 35 | print('type.__weakrefoffset__ = ', type.__weakrefoffset__) 36 | print('int.__weakrefoffset__ = ', int.__weakrefoffset__) 37 | print('str.__weakrefoffset__ = ', str.__weakrefoffset__) 38 | print('bool.__weakrefoffset__ = ', bool.__weakrefoffset__) 39 | print('list.__weakrefoffset__ = ', list.__weakrefoffset__) 40 | print('dict.__weakrefoffset__ = ', dict.__weakrefoffset__) 41 | print('tuple.__weakrefoffset__ = ', tuple.__weakrefoffset__) 42 | print('set.__weakrefoffset__ = ', set.__weakrefoffset__) 43 | print('float.__weakrefoffset__ = ', float.__weakrefoffset__) 44 | 45 | # Вывод 46 | # Function.__weakrefoffset__ = 24 47 | # type.__weakrefoffset__ = 368 48 | # int.__weakrefoffset__ = 0 49 | # str.__weakrefoffset__ = 0 50 | # bool.__weakrefoffset__ = 0 51 | # list.__weakrefoffset__ = 0 52 | # dict.__weakrefoffset__ = 0 53 | # tuple.__weakrefoffset__ = 0 54 | # set.__weakrefoffset__ = 192 55 | # float.__weakrefoffset__ = 0 56 | ``` 57 | -------------------------------------------------------------------------------- /Theory/Part_9/Module_webbrowser.md: -------------------------------------------------------------------------------- 1 | Модуль `webbrowser` 2 | --- 3 | --- 4 | Стандартный модуль, открывает в браузере `url` ссылку. 5 | 6 | Данный пример, открывает дефолтный в системе браузер, и 7 | идет на стр https://yandex.ru/maps куда передает адрес, 8 | что передан из терминала или буфер обмена, и мы получаем 9 | этот адрес. 10 | Данный пример, открывает дефолтный браузер системы, и идет 11 | на ресурс https://yandex.ru/maps гугл карт, если при 12 | запуске был передан адрес для поиска то по нему и будет 13 | идти поиск местоположения, если параметра для поиска при 14 | запуске не передано, то адрес будет взят из буфера обмена. 15 | 16 | ```python 17 | import webbrowser 18 | import sys 19 | import pyperclip 20 | from urllib import parse 21 | 22 | if len(sys.argv) > 1: 23 | address = ' '.join(sys.argv[1:]) 24 | else: 25 | address = pyperclip.paste() 26 | 27 | address = parse.urlencode({'text': address}) 28 | webbrowser.open('https://yandex.ru/maps/?' + address) 29 | ``` 30 | 31 | Можно самому выбирать в каком браузере открывать ресурс. 32 | 33 | Данный пример открывает в chrome песню с youtube "сердце хана". 34 | ```python 35 | import webbrowser 36 | 37 | khan_heart_url = "https://www.youtube.com/watch?v=BhbsaGmd3EM&list=PLJwYC3yCHjKsqDQkLKb1yPQ96OX9PBYg6&index=14" 38 | webbrowser.get(using='google-chrome').open_new_tab(khan_heart_url) 39 | ``` -------------------------------------------------------------------------------- /Theory/Part_9/Pydentic.md: -------------------------------------------------------------------------------- 1 | Модуль Pydentic 2 | --- 3 | 4 | Модуль python для валидации данных, проверки данных на соответствие 5 | модели данных, валидации аргументов функций в соответствии с аннотациями. 6 | 7 | Установка 8 | 9 | pip install Pydentic 10 | 11 | --- 12 | 13 | `validate_arguments` - декоратор для валидации аргументов функции на 14 | соответствие типам данных описанных в аннотациях этого метода. 15 | 16 | ```python 17 | from pydantic import validate_arguments 18 | 19 | @validate_arguments 20 | def func_1(arg1: str, arg2: int, arg3: list) -> bool: 21 | pass 22 | 23 | func_1() 24 | ``` 25 | 26 | --- 27 | 28 | С помощью `pydantic`, можно определять модель с описанием структуры данных, 29 | данные будут валидироваться по описанной для них аннотации, поддерживается 30 | аннотация с помощью модуля `typing`. 31 | 32 | ```python 33 | from pydantic import BaseModel 34 | 35 | class PersonModel(BaseModel): 36 | name: str 37 | age: int 38 | ``` 39 | 40 | Для более сложной валидации данных, `pydantic` предоставляет 2 декоратора: 41 | 42 | `@validator("название атрибута")` - метод принимает одно значение, значение 43 | конкретного атрибута модели, и проверяет его, если проверка не пройдена то 44 | вызываем исключение `ValueError`. 45 | 46 | `@root_validator` - метод принимает все атрибуты модели, что позволяет делать 47 | сложные проверки с участием всех атрибутов модели. 48 | 49 | Пример модели для валидации данных 50 | ```python 51 | from typing import List, Union 52 | from pydantic import BaseModel, validator, root_validator 53 | from datetime import datetime 54 | 55 | class SearchModel(BaseModel): 56 | """Validate model for Search parameters in Google Earth Engine.""" 57 | category: Category # Класс категории 58 | subjects: List[Subject] # Класс объекта 59 | age: int 60 | start_date: datetime 61 | end_date: datetime 62 | married: bool 63 | name: str 64 | 65 | @validator("age") 66 | def check_age(cls, age): 67 | """Проверка возраста""" 68 | if 18 <= age <= 100: 69 | raise ValueError("Age error") 70 | return age 71 | 72 | @root_validator 73 | def check_date_range(cls, values): 74 | """Проверка дат""" 75 | start_date, end_date = values["start_date"], values["end_date"] 76 | if end_date >= start_date: 77 | raise ValueError("Data range error") 78 | return values 79 | 80 | @root_validator 81 | def check_subjects(cls, values): 82 | """Проверяем что все субьекты принадлежат одной категории""" 83 | category, subjects = values["category"], values["subjects"] 84 | for sub in subjects: 85 | if sub.category.id != category.id: 86 | ValueError("Not all subject in onne category") 87 | return values 88 | ``` 89 | -------------------------------------------------------------------------------- /Theory/Part_9/argparse.md: -------------------------------------------------------------------------------- 1 | Модуль argparse 2 | --- 3 | 4 | Это модуль позволяющий нам работать с аргументами переданными в скрипт python 5 | через терминал, с его помощью можно сделать программу гибкой, задавая нужное 6 | программы в зависимости от получаемых параметров. 7 | 8 | Пример 9 | ```python 10 | import argparse 11 | 12 | # создание нового объекта argparse с описанием 13 | parser = argparse.ArgumentParser(description='Service version #1') 14 | 15 | # указываем какие обязательные аргументы может принимать скрипт 16 | parser.add_argument('arg_int', type=int, help='Input dir for videos') 17 | parser.add_argument('arg_str', type=str, help='Output dir for videos') 18 | 19 | # получаем аргументы, которые может принимать скрипт 20 | parser_args = parser.parse_args() 21 | print(parser_args) 22 | ``` 23 | 24 | --- 25 | 26 | ```python 27 | import parser 28 | 29 | # указываем аргумент с дефолтным значением 30 | parser_arge = parser.add_argument( 31 | '-m', 32 | type=int, 33 | default=2, 34 | help='Provide an integer, default: 2' 35 | ) 36 | 37 | # Получаем значение переданного параметра 38 | print(parser_arge.m) 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /Theory/Part_9/jsonschema.md: -------------------------------------------------------------------------------- 1 | Модуль `jsonschema` 2 | --- 3 | 4 | Схема - некая структура вложенности объектов, параметров, данных переменных, к 5 | примеру схемой можно назвать `POST` запрос фронта на точку API сервера, в виде 6 | `JSON` тела со следующей структурой. 7 | 8 | Вся эта структура с ее вложенностью и есть то что можно назвать схемой 9 | ```json 10 | { 11 | "count": 100, 12 | "params": { 13 | "number": { 14 | "min": 1, 15 | "max": 100 16 | }, 17 | "type": 55 18 | } 19 | } 20 | ``` 21 | 22 | --- 23 | 24 | Другой пример, представим себе что мы используем `GeoPandas` для сохранения `.shp` 25 | файла с геометрией и атрибутами полей. 26 | 27 | ```python 28 | # схема по сохранения полей в выходной файл 29 | SCHEMA = { 30 | "geometry": "Unknown", 31 | 'properties': { 32 | 'uuid': 'int', 33 | 'attr1': 'str', 34 | 'attr2': 'date', 35 | 'attr3': 'str', 36 | 'attr4': 'float' 37 | } 38 | } 39 | 40 | # сохраняем GeoDataFrame в выходной файл 41 | geo_df.to_file( 42 | path_to_save.as_posix(), # путь к сохраняемому файлу 43 | mode='w', # модификатор доступа 44 | encoding='UTF-8', # кодировка 45 | schema=SCHEMA # указывем схему сохранения 46 | ) 47 | ``` 48 | 49 | --- 50 | 51 | Другой пример, это обычные объекты с вложенными объектами 52 | 53 | ```python 54 | class A: 55 | name = 'name' 56 | number = 55 57 | list = [1, 2, 3, 4, 5] 58 | 59 | def __init__(self, obj): 60 | self.inner_obj = obj 61 | 62 | class B: 63 | name = 'name2' 64 | number = 100 65 | 66 | a = A(obj=B()) 67 | 68 | # Структуру объекта A можно представить: 69 | struct = { 70 | "name": "name", 71 | "number": 55, 72 | "list": [1, 2, 3, 4, 5], 73 | "inner_obj": { 74 | "name": "name2", 75 | "number": 100 76 | } 77 | } 78 | ``` 79 | 80 | --- 81 | 82 | `jsonschema` - модуль для проверки соответствия (объекта, словаря, `json` ...) 83 | заданной схему с указанием типов данных, это полезно использовать при валидации 84 | запросов/ответов от API и содержимого json файлов, то есть мы можем описать схему 85 | данных, и проверять соответствие объекта этой самой схеме, что сразу и является его 86 | валидацией, то есть пройдя проверку, мы можем быть уверены, что объект соответствует 87 | указанным нами требованиям, и что объект пригоден к последующей обработке. 88 | 89 | Установка 90 | ``` 91 | pip install jsonschema 92 | ``` 93 | 94 | Общая суть модуля проста, мы описываем правила валидации, нахождения определенных 95 | атрибутов с указанием какие из атрибутов являются обязательными, и описываем типы 96 | данных. 97 | 98 | Вот пример того как можно удобно валидировать структуру данных на соответствие схеме: 99 | ```python 100 | import jsonschema 101 | def validate_structure_by_schema(input_data, schema): 102 | """ 103 | Проверяет структуру на соответствие установленной схеме данных 104 | """ 105 | try: 106 | jsonschema.validate(instance=input_data, schema=schema) 107 | except jsonschema.exceptions.ValidationError as e: 108 | return False 109 | return True 110 | ``` 111 | 112 | Наша структура 113 | ```json 114 | { 115 | "count": 100, 116 | "params": { 117 | "number": { 118 | "min": 1, 119 | "max": 100 120 | }, 121 | "type": 55 122 | } 123 | } 124 | ``` 125 | 126 | Опишем правила валидации для этой структуры: 127 | ```python 128 | SCHEMA_FOR_VALIDATION = { 129 | "type": "object", # указываем тип объекта 130 | "properties": { # свойства которые должны быть у этого объекта 131 | "count": { # название поля которое должно быть и вложенная структура 132 | "type": "integer", # тип данных число 133 | "minimum": 1, # минимальное значение 134 | "maximum": 100 # максимальное значение 135 | }, 136 | "params": { 137 | "type": "object", 138 | "properties": { 139 | "number": { 140 | "type": "object", 141 | "properties": { 142 | "min": {"type": "integer", "minimum": 1}, 143 | "max": {"type": "integer", "maximum": 1000}, 144 | }, 145 | "required": ['min', 'max'] 146 | }, 147 | "type": {"type": "integer", "minimum": 1}, 148 | }, 149 | "required": ['number'] 150 | } 151 | }, 152 | "required": [ # указываем какие атрибуты должны быть обязательными на этом уровне 153 | 'count', 154 | 'params' 155 | ] 156 | } 157 | ``` 158 | -------------------------------------------------------------------------------- /Theory/Part_9/logger.md: -------------------------------------------------------------------------------- 1 | Логирование 2 | --- 3 | 4 | [Документация логирования](https://djangodoc.ru/3.2/topics/logging/) 5 | 6 | У самого языка `Python` есть свой собственный встроенный модуль для 7 | логирования `logging` 8 | 9 | Пример работы 10 | ```python 11 | import logging 12 | 13 | logger = logging.getLogger('logger_for_debug') 14 | 15 | def some_function(): 16 | if False: 17 | logger.error('Ошибка ...') 18 | ``` 19 | 20 | `logging.getLogger()` - получает или если не существовало ранее, создает 21 | экземпляр регистратора для логирования сообщений, имя регистратора будет 22 | его уникальным идентификатором. 23 | 24 | Виды логирования: 25 | 26 | - `logger.debug()` 27 | - `logger.info()` 28 | - `logger.warning()` 29 | - `logger.error()` 30 | - `logger.critical()` 31 | 32 | --- 33 | Ведение журнала для логирования. 34 | 35 | Настроить журнал ведения логирования можно по разному, чаще используют 36 | способ через словарь `LOGGING`. 37 | 38 | `LOGGING` - словарь с параметрами который будет описывать как вести журнал 39 | логирования, фильтры и средства форматирования для ведения логов. 40 | 41 | Настройки `settings.py` с параметрами `LOGGING` для ведения журнала: 42 | ```python 43 | import os 44 | 45 | LOGGING = { 46 | 'version': 1, 47 | 'disable_existing_loggers': False, 48 | 'handlers': { 49 | 'console': { 50 | 'class': 'logging.StreamHandler', 51 | }, 52 | }, 53 | 'root': { 54 | 'handlers': ['console'], 55 | 'level': 'WARNING', 56 | }, 57 | 'loggers': { 58 | 'django': { 59 | 'handlers': ['console'], 60 | 'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'), 61 | 'propagate': False, 62 | }, 63 | }, 64 | } 65 | ``` 66 | 67 | --- 68 | Запись логов в файл 69 | --- 70 | 71 | Записываем результаты логирования в файл, с очищением перед каждым сеансом. 72 | 73 | ```python 74 | import logging 75 | 76 | logging.basicConfig(filemode='w', 77 | format='%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s', 78 | level=logging.INFO, 79 | filename='logging.log' 80 | ) 81 | -------------------------------------------------------------------------------- /questions.md: -------------------------------------------------------------------------------- 1 | 2 | 1) Регрессионные тесты 3 | 2) Модульные тесты 4 | 3) Unit - тесты 5 | 4) webhook 6 | 5) Функциональные тесты 7 | 8 | ### Предикаты 9 | ### Async Python 10 | ### defaultdict или OrderedDict. 11 | ### Функция callback() 12 | ### тротлинга запросов 13 | ### защиты от фрода 14 | ### LeetCode 15 | ### ETL-решение 16 | ### GC 17 | ### AsyncIO 18 | ### Потоки ввода и вывода sys.__stdin__ sys.__stdout__ sys.__stderr__ 19 | ### Потоки ввода и вывода в купе с print(file=file) 20 | ### Что такое allocators 21 | 22 | ### Динамическая загрузка модуля. Модуль importlib 23 | import importlib 24 | ### Модуль shutil для работы с файлами 25 | import shutil 26 | ### Модуль traceback для трассировки кода 27 | ### Модуль itertools 28 | 29 | ### Лацируется память 30 | ### Хинты 31 | ### Бенчмарк 32 | ### virtualenwrapper 33 | ### Какой тип у файла ? 34 | ### time and timeit 35 | ### Лексически обл видимости в питоне и не только 36 | ### Unit есты 37 | ### Обьеденение кортежей работате за линию ? константу ? 38 | ### Карутины 39 | ### Асинхронное программирование в Python — это мозгодробительная штука 40 | ### Модуль reeder 41 | ### @functools 42 | ### @functools.lru_cache() 43 | ### @functools.wraps 44 | ### @dataclass Классы данных python -m pip install dataclasses 45 | ### Файловые обьекты, файлы это обьекты ? 46 | ### Переменные продолж существ даже после выхода из for 47 | ### Модуль это класс print(type(time)) 48 | ### Пайплайн 49 | ### аллоцируется 50 | ### Модуль functools 51 | 52 | ### Не обезательно 53 | ### Модуль struct для сокращения потребления памяти. 54 | ### Модуль memoryview для сокращения потребления памяти. 55 | 56 | ### Мемоизация и Каррирование 57 | Мемоизация - метод сохранения результатов превыдущих вычеслений для 58 | ускорения работы, если такие аргументы уже приходили то в место повторного 59 | вычисления, отдаем уже сохраненные вычисления что были сохранены. 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | --------------------------------------------------------------------------------