├── .flake8 ├── lesson-01 ├── lesson-01.pdf ├── vk_api.py ├── user.py ├── homework.md ├── test_user.py └── class_01.ipynb ├── lesson-02 ├── lesson-02.pdf └── homework.md ├── lesson-03 ├── lesson-03.pdf └── homework.md ├── lesson-04 ├── lesson-04.pdf └── homework.md ├── lesson-05 ├── lesson-05.pdf └── homework.md ├── lesson-06 ├── lesson-06.pdf ├── homework.md └── class_06.ipynb ├── lesson-07 ├── lesson-07.pdf ├── src │ ├── socket_server.py │ ├── select_socket.py │ ├── selectors_socket.py │ └── generator_socket.py └── homework.md ├── lesson-08 ├── lesson-08.pdf ├── homework.md └── class_08.ipynb ├── lesson-09 ├── lesson-09.pdf └── homework.md ├── lesson-10 ├── lesson-10.pdf ├── src │ ├── lib_cffi │ │ ├── tmp_mult.o │ │ ├── test_cffi.py │ │ └── tmp_mult.c │ ├── lib_cython │ │ ├── setup.py │ │ └── fibcyth.pyx │ ├── lib_capi │ │ ├── setup.py │ │ └── fibutils.c │ ├── lib_ctypes │ │ ├── fibutils.c │ │ └── test_fibutils.py │ └── perf.py └── homework.md ├── lesson-11 ├── lesson-11.pdf └── check_hints.py ├── requirements.txt ├── .pylintrc ├── .coveragerc ├── .github └── workflows │ └── validation.yml ├── README.md └── .gitignore /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 80 3 | extend-ignore = F403, F405, F401 4 | -------------------------------------------------------------------------------- /lesson-01/lesson-01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-01/lesson-01.pdf -------------------------------------------------------------------------------- /lesson-02/lesson-02.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-02/lesson-02.pdf -------------------------------------------------------------------------------- /lesson-03/lesson-03.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-03/lesson-03.pdf -------------------------------------------------------------------------------- /lesson-04/lesson-04.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-04/lesson-04.pdf -------------------------------------------------------------------------------- /lesson-05/lesson-05.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-05/lesson-05.pdf -------------------------------------------------------------------------------- /lesson-06/lesson-06.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-06/lesson-06.pdf -------------------------------------------------------------------------------- /lesson-07/lesson-07.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-07/lesson-07.pdf -------------------------------------------------------------------------------- /lesson-08/lesson-08.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-08/lesson-08.pdf -------------------------------------------------------------------------------- /lesson-09/lesson-09.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-09/lesson-09.pdf -------------------------------------------------------------------------------- /lesson-10/lesson-10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-10/lesson-10.pdf -------------------------------------------------------------------------------- /lesson-11/lesson-11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-11/lesson-11.pdf -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.10.5 2 | 3 | flake8==7.1.0 4 | pylint==3.2.7 5 | pytest==8.3.2 6 | coverage==7.6.1 7 | -------------------------------------------------------------------------------- /lesson-01/vk_api.py: -------------------------------------------------------------------------------- 1 | def fetch_vk_api(path, username, part): 2 | # requests.get(path, ...) 3 | raise NotImplementedError 4 | -------------------------------------------------------------------------------- /lesson-10/src/lib_cffi/tmp_mult.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailcourses/deep_python_autumn_2024/HEAD/lesson-10/src/lib_cffi/tmp_mult.o -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | disable= 3 | C0114, # missing-module-docstring 4 | C0115, 5 | C0116, 6 | 7 | [FORMAT] 8 | max-line-length=80 9 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [report] 2 | exclude_also = 3 | logger\.info\(.*\) 4 | if __name__ == .__main__.: 5 | fail_under = 90 6 | precision = 2 7 | show_missing = true 8 | -------------------------------------------------------------------------------- /lesson-10/src/lib_cython/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from Cython.Build import cythonize 3 | 4 | 5 | def main(): 6 | setup( 7 | ext_modules=cythonize(["fibcyth.pyx"]), 8 | ) 9 | 10 | 11 | if __name__ == "__main__": 12 | main() 13 | -------------------------------------------------------------------------------- /lesson-10/src/lib_capi/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, Extension 2 | 3 | 4 | def main(): 5 | setup( 6 | name="fibutils", 7 | version="1.0.1", 8 | ext_modules=[Extension("fibutils", ["fibutils.c"])], 9 | ) 10 | 11 | 12 | if __name__ == "__main__": 13 | main() 14 | -------------------------------------------------------------------------------- /lesson-10/src/lib_cython/fibcyth.pyx: -------------------------------------------------------------------------------- 1 | cpdef fib_rec_cy(int n): 2 | if n < 3: 3 | return 1 4 | 5 | return fib_rec_cy(n - 1) + fib_rec_cy(n - 2) 6 | 7 | 8 | cpdef fib_iter_cy(int n): 9 | cdef int a = 0 10 | cdef int b = 1 11 | 12 | for _ in range(n): 13 | a, b = b, a + b 14 | 15 | return a 16 | -------------------------------------------------------------------------------- /lesson-10/src/lib_ctypes/fibutils.c: -------------------------------------------------------------------------------- 1 | int fib_rec_ctypes(int n) 2 | { 3 | if (n < 3) 4 | return 1; 5 | 6 | return fib_rec_ctypes(n - 1) + fib_rec_ctypes(n - 2); 7 | } 8 | 9 | 10 | int fib_iter_ctypes(int n) 11 | { 12 | int a = 0; 13 | int b = 1; 14 | 15 | for (int i = 0; i < n; ++i) 16 | { 17 | int tmp = b; 18 | b = a + b; 19 | a = tmp; 20 | } 21 | 22 | return a; 23 | } 24 | 25 | 26 | int sum(int* arr, int len) 27 | { 28 | int s = 0; 29 | for (int i = 0; i < len; ++i) 30 | { 31 | s += arr[i]; 32 | } 33 | return s; 34 | } 35 | -------------------------------------------------------------------------------- /lesson-07/src/socket_server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | 4 | # server_sock = socket.socket() 5 | server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 6 | server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 7 | server_sock.bind(("localhost", 15000)) 8 | 9 | server_sock.listen(2) 10 | 11 | while True: 12 | client_sock, addr = server_sock.accept() 13 | print("client connected", addr) 14 | 15 | while True: 16 | # data = client_sock.recv(4) # http 17 | data = client_sock.recv(4096) 18 | if not data: 19 | break 20 | else: 21 | client_sock.send(data.decode().upper().encode()) 22 | 23 | client_sock.close() 24 | print("client gone:", addr) 25 | -------------------------------------------------------------------------------- /lesson-07/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #07 (async) 2 | 3 | ### 1. Скрипт для асинхронной обкачки урлов 4 | Написать скрипт для обкачки списка урлов из файла с возможностью задавать количество одновременных запросов, используя асинхронное программирование. 5 | Клиент можно использовать любой, например, из aiohttp. 6 | Например, 10 одновременных запросов могут задаваться командой: 7 | 8 | `python fetcher.py -c 10 urls.txt` 9 | или 10 | `python fetcher.py 10 urls.txt` 11 | 12 | Код должен быть выделен в функции и/или классы и методы. 13 | 14 | ### 2. Тесты в отдельном модуле 15 | 16 | ### 3. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 17 | 18 | ### 4. Покрытие тестов через coverage 19 | 20 | ### 5. Зеленый пайплайн в репе 21 | -------------------------------------------------------------------------------- /lesson-01/user.py: -------------------------------------------------------------------------------- 1 | from vk_api import fetch_vk_api 2 | 3 | 4 | class User: 5 | def __init__(self, name, age): 6 | self.name = name 7 | self.age = age 8 | 9 | def greetings(self): 10 | return f"Hello, {self.name}!" 11 | 12 | def birthday(self): 13 | self.age += 1 14 | return self.age 15 | 16 | def get_friends(self, name_part=None): 17 | if name_part: 18 | name_part = name_part.upper() 19 | 20 | friends = fetch_vk_api( 21 | "/friends", self.name, part=name_part 22 | ) 23 | 24 | if name_part is not None: 25 | name_part = name_part.lower() 26 | friends = [ 27 | fr for fr in friends if name_part in fr 28 | ] 29 | 30 | return friends 31 | -------------------------------------------------------------------------------- /lesson-10/src/lib_ctypes/test_fibutils.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | 3 | 4 | def load_sum(): 5 | lib = ctypes.cdll.LoadLibrary("./libfibutils.so") 6 | lib.sum.argstype = [ctypes.POINTER(ctypes.c_int), ctypes.c_int] 7 | lib.sum.restype = ctypes.c_int 8 | 9 | lst = list(range(10, 20)) 10 | len_lst = len(lst) 11 | 12 | arr_int_type = ctypes.c_int * len_lst 13 | res = lib.sum(arr_int_type(*lst), len_lst) 14 | 15 | print(f"{res=}, {sum(lst)}") 16 | 17 | 18 | def load_std(): 19 | lib = ctypes.CDLL(None) 20 | lib.strstr.argstype = [ctypes.c_char_p, ctypes.c_char_p] 21 | lib.strstr.restype = ctypes.c_char_p 22 | 23 | print(f'{lib.strstr(b"ababc", b"ba")=}') 24 | print(f'{lib.strstr(b"ababc", b"qwerrt")=}') 25 | print(f'{lib.strstr(b"ababc", b"bc")=}') 26 | 27 | 28 | def run(): 29 | load_sum() 30 | load_std() 31 | 32 | 33 | if __name__ == "__main__": 34 | run() 35 | -------------------------------------------------------------------------------- /.github/workflows/validation.yml: -------------------------------------------------------------------------------- 1 | name: Validation 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | validate_homeworks: 13 | name: Validate all homeworks 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-python@v5.2.0 19 | with: 20 | python-version: '3.12' 21 | cache: 'pip' 22 | 23 | - name: Install dependencies 24 | run: pip install -r requirements.txt 25 | 26 | - name: Check flake8 27 | run: flake8 . 28 | 29 | - name: Check pylint 30 | if: ${{ always() }} 31 | run: pylint ./*/*.py 32 | 33 | - name: Check tests with pytest 34 | if: ${{ always() }} 35 | run: coverage run -m pytest . 36 | 37 | - name: Check test coverage 38 | run: coverage report -m 39 | -------------------------------------------------------------------------------- /lesson-10/src/lib_cffi/test_cffi.py: -------------------------------------------------------------------------------- 1 | import cffi 2 | 3 | 4 | def load_sum(): 5 | ffi = cffi.FFI() 6 | lib = ffi.dlopen("../lib_ctypes/libfibutils.so") 7 | 8 | ffi.cdef("int sum(int* arr, int len);") 9 | 10 | lst = list(range(10, 20)) 11 | len_lst = len(lst) 12 | 13 | arr = ffi.new("int[]", lst) 14 | print(arr) 15 | 16 | res = lib.sum(arr, len_lst) 17 | print(f"{res=}, {sum(lst)}") 18 | 19 | 20 | def load_build(): 21 | builder = cffi.FFI() 22 | builder.cdef("int mult(int a, int b, int c);") 23 | 24 | builder.set_source( 25 | "tmp_mult", 26 | """ 27 | int mult(int a, int b, int c) 28 | { 29 | int res = 0; 30 | res = a * b * c; 31 | return res; 32 | } 33 | """ 34 | ) 35 | builder.compile() 36 | 37 | 38 | from tmp_mult import lib 39 | 40 | a, b, c = 2, 5, 9 41 | res = lib.mult(a, b, c) 42 | print(f"{res=}, {a * b * c=}") 43 | 44 | 45 | def run(): 46 | load_sum() 47 | load_build() 48 | 49 | 50 | if __name__ == "__main__": 51 | run() 52 | -------------------------------------------------------------------------------- /lesson-07/src/select_socket.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from select import select 3 | 4 | to_monitor = [] 5 | 6 | server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 8 | server_sock.bind(("localhost", 16000)) 9 | server_sock.listen(5) 10 | 11 | 12 | def accept_conn(server_sock): 13 | client_sock, addr = server_sock.accept() 14 | print("Connect", addr) 15 | to_monitor.append(client_sock) 16 | 17 | 18 | def respond(client_sock): 19 | data = client_sock.recv(4096) 20 | 21 | if data: 22 | client_sock.send(data.decode().upper().encode()) 23 | else: 24 | print("client closed") 25 | client_sock.close() 26 | to_monitor.remove(client_sock) 27 | 28 | 29 | def event_loop(): 30 | while True: 31 | ready_to_read, _, _ = select(to_monitor, [], []) # read, write, err 32 | for sock in ready_to_read: 33 | if sock is server_sock: 34 | accept_conn(sock) 35 | else: 36 | respond(sock) 37 | 38 | 39 | if __name__ == "__main__": 40 | to_monitor.append(server_sock) 41 | event_loop() 42 | -------------------------------------------------------------------------------- /lesson-05/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #05 (стандартная библиотека) 2 | 3 | ### 1. LRU-кэш 4 | Интерфейс: 5 | 6 | ```py 7 | class LRUCache: 8 | 9 | def __init__(self, limit=42): 10 | pass 11 | 12 | def get(self, key): 13 | pass 14 | 15 | def set(self, key, value): 16 | pass 17 | 18 | 19 | cache = LRUCache(2) 20 | 21 | cache.set("k1", "val1") 22 | cache.set("k2", "val2") 23 | 24 | assert cache.get("k3") is None 25 | assert cache.get("k2") == "val2" 26 | assert cache.get("k1") == "val1" 27 | 28 | cache.set("k3", "val3") 29 | 30 | assert cache.get("k3") == "val3" 31 | assert cache.get("k2") is None 32 | assert cache.get("k1") == "val1" 33 | 34 | 35 | Если удобнее, get/set можно сделать по аналогии с dict: 36 | cache["k1"] = "val1" 37 | print(cache["k3"]) 38 | ``` 39 | 40 | Сложность решения по времени в среднем должна быть константной O(1). 41 | Реализация любым способом без использования OrderedDict. 42 | 43 | ### 2. Тесты в отдельном модуле 44 | 45 | ### 3. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 46 | 47 | ### 4. Покрытие тестов через coverage 48 | 49 | ### 5. Зеленый пайплайн в репе 50 | -------------------------------------------------------------------------------- /lesson-09/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #09 (логирование) 2 | 3 | ### 1. Логирование LRUCache (hw #05) 4 | 5 | - Нужно добавить логирование разного уровня в файл cache.log. 6 | - По аргументу командной строки "-s" дополнительно логировать в stdout с отдельным форматированием. 7 | - По аргументу командной строки "-f" нужно применять кастомный фильтр, например, отбрасывающий записи c четным числом слов или что-то свое. 8 | - "-s" и "-f" могут указываеться в одном запуске и должны работать вместе в таком случае (модуль argparse). 9 | 10 | Логирование должно покрывать как минимум следующие случаи: 11 | - get существующего ключа 12 | - get отсутствующего ключа 13 | - set отсутствующего ключа 14 | - set отсутствующего ключа, когда достигнута ёмкость 15 | - set существующего ключа 16 | - различные debug записи в дополнение и в зависимости от реализации 17 | 18 | При запуске модуля должны выполняться все перечисленные операции с кэшом (через функцию в `if __name__ == "__main__"`). 19 | 20 | Код решения должен быть целиком в каталоге данного ДЗ без ссылок/импортов на домашки про LRUCache. 21 | Корректность LRUCache в данном задании не проверяется. 22 | 23 | ### 2. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 24 | 25 | ### 3. Зеленый пайплайн в репе 26 | -------------------------------------------------------------------------------- /lesson-07/src/selectors_socket.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import selectors 3 | 4 | selector = selectors.DefaultSelector() 5 | print("selector", selector) 6 | 7 | 8 | def server(): 9 | server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 10 | server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 11 | server_sock.bind(("localhost", 17000)) 12 | server_sock.listen(5) 13 | 14 | selector.register(server_sock, selectors.EVENT_READ, accept_conn) 15 | 16 | 17 | def accept_conn(server_sock): 18 | client_sock, addr = server_sock.accept() 19 | print("Connect", addr) 20 | selector.register(client_sock, selectors.EVENT_READ, respond) 21 | 22 | 23 | def respond(client_sock): 24 | data = client_sock.recv(4096) 25 | 26 | if data: 27 | client_sock.send(data.decode().upper().encode()) 28 | else: 29 | print("close client") 30 | selector.unregister(client_sock) 31 | client_sock.close() 32 | 33 | 34 | def event_loop(): 35 | while True: 36 | events = selector.select() # (key, events_mask) 37 | 38 | for key, _ in events: 39 | # key: NamedTuple(fileobj, events, data) 40 | callback = key.data 41 | callback(key.fileobj) 42 | 43 | 44 | if __name__ == "__main__": 45 | server() 46 | event_loop() 47 | -------------------------------------------------------------------------------- /lesson-10/src/lib_capi/fibutils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | int fib_rec_capi_impl(int n) 8 | { 9 | if (n < 3) 10 | return 1; 11 | 12 | return fib_rec_capi_impl(n - 1) + fib_rec_capi_impl(n - 2); 13 | } 14 | 15 | 16 | PyObject* fibutils_fib_rec_capi(PyObject* self, PyObject* args) 17 | { 18 | int n = 0; 19 | if (!PyArg_ParseTuple(args, "i", &n)) 20 | { 21 | printf("WRONG arg"); 22 | return NULL; 23 | } 24 | 25 | int res = fib_rec_capi_impl(n); 26 | return PyLong_FromLong(res); 27 | /* return Py_BuildValue(res); */ 28 | } 29 | 30 | 31 | PyObject* fibutils_fib_iter_capi(PyObject* self, PyObject* args) 32 | { 33 | int n = 0; 34 | if (!PyArg_ParseTuple(args, "i", &n)) 35 | { 36 | printf("WRONG arg"); 37 | return NULL; 38 | } 39 | 40 | int a = 0; 41 | int b = 1; 42 | 43 | for (int i = 0; i < n; ++i) 44 | { 45 | int tmp = b; 46 | b = a + b; 47 | a = tmp; 48 | } 49 | return PyLong_FromLong(a); 50 | } 51 | 52 | 53 | static PyMethodDef methods[] = { 54 | {"fib_rec_capi", fibutils_fib_rec_capi, METH_VARARGS, "c-api fib rec"}, 55 | {"fib_iter_capi", fibutils_fib_iter_capi, METH_VARARGS, "c-api fib iter"}, 56 | {NULL, NULL, 0, NULL} 57 | }; 58 | 59 | 60 | static struct PyModuleDef module_fibutils = { 61 | PyModuleDef_HEAD_INIT, "fibutils", NULL, -1, methods 62 | }; 63 | 64 | 65 | PyMODINIT_FUNC PyInit_fibutils() 66 | { 67 | return PyModule_Create( &module_fibutils ); 68 | } 69 | -------------------------------------------------------------------------------- /lesson-08/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #08 (память, профилирование) 2 | 3 | ### 1. Сравнение использования weakref и слотов 4 | Нужно придумать свои типы с несколькими атрибутами: 5 | - класс с обычными атрибутами 6 | - класс со слотами 7 | - класс с атрибутами weakref 8 | 9 | Для каждого класса создается большое число экземпляров и замеряется (сравнивается): 10 | - время создания пачки экземпляров 11 | - время чтения/изменения атрибутов 12 | 13 | Результаты замеров оформляются скриншотами c описанием и выводом. 14 | 15 | ### 2. Профилирование 16 | Провести профилирование вызовов и памяти для кода из пункта 1. 17 | 18 | Результаты оформляются скриншотами c описанием. 19 | 20 | ### 3. Декоратор для профилирования 21 | Применение декоратора к функции должно выполнять прoфилирование (cProfile) всех вызовов данной функции. 22 | Вызов метода `.print_stat()` должен выводить единую таблицу со статистикой профилирования суммарно по всем вызовам функции. 23 | 24 | 25 | ```py 26 | def profile_deco(...): 27 | ... 28 | 29 | 30 | @profile_deco 31 | def add(a, b): 32 | return a + b 33 | 34 | 35 | @profile_deco 36 | def sub(a, b): 37 | return a - b 38 | 39 | 40 | add(1, 2) 41 | add(4, 5) 42 | sub(4, 5) 43 | 44 | 45 | add.print_stat() # выводится результат профилирования суммарно по всем вызовам функции add (всего два вызова) 46 | sub.print_stat() # выводится результат профилирования суммарно по всем вызовам функции sub (всего один вызов) 47 | ``` 48 | 49 | ### 4. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 50 | 51 | ### 5. Зеленый пайплайн в репе 52 | -------------------------------------------------------------------------------- /lesson-07/src/generator_socket.py: -------------------------------------------------------------------------------- 1 | # David Beazley algo 2 | import socket 3 | from select import select 4 | 5 | 6 | tasks = [] 7 | # sock: gen 8 | to_read = {} 9 | to_write = {} 10 | 11 | 12 | def server(): 13 | server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 14 | server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 15 | server_sock.bind(("localhost", 25000)) 16 | server_sock.listen() 17 | 18 | while True: 19 | yield "read", server_sock 20 | client_sock, addr = server_sock.accept() # read 21 | print("connect from", addr) 22 | 23 | tasks.append(client(client_sock)) 24 | 25 | 26 | def client(client_sock): 27 | while True: 28 | yield "read", client_sock 29 | data = client_sock.recv(4096) # read 30 | 31 | if not data: 32 | break 33 | else: 34 | yield "write", client_sock 35 | client_sock.send(data.decode().upper().encode()) # write 36 | 37 | client_sock.close() 38 | 39 | 40 | def event_loop(): 41 | while any([tasks, to_read, to_write]): 42 | 43 | while not tasks: 44 | ready_to_read, ready_to_write, _ = select(to_read, to_write, []) 45 | 46 | for sock in ready_to_read: 47 | tasks.append(to_read.pop(sock)) 48 | 49 | for sock in ready_to_write: 50 | tasks.append(to_write.pop(sock)) 51 | 52 | try: 53 | task = tasks.pop(0) 54 | op_type, sock = next(task) 55 | 56 | if op_type == "read": 57 | to_read[sock] = task 58 | elif op_type == "write": 59 | to_write[sock] = task 60 | 61 | except StopIteration: 62 | pass 63 | 64 | 65 | if __name__ == "__main__": 66 | tasks.append(server()) 67 | event_loop() 68 | -------------------------------------------------------------------------------- /lesson-06/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #06 (потоки, процессы) 2 | 3 | ### 1. Клиент-серверное приложение для обкачки набора урлов с ограничением нагрузки 4 | #### Cервер 5 | master-worker cервер для обработки запросов от клиента. 6 | 7 | Алгоритм должен быть следующим: 8 | 9 | - Сервер должен поддерживать взаимодействие с любым числом клиентов; 10 | - Мастер и воркеры это разные потоки в едином приложении сервера; 11 | - Количество воркеров задается при запуске; 12 | - Мастер слушает порт, на который клиенты будут по TCP отправлять урлы для обкачки; 13 | - Мастер принимает запроc и передает его одному из воркеров; 14 | - Воркер читает url от клиента; 15 | - Воркер обкачивает url по http и возвращает клиенту топ K самых частых слов и их частоту в формате json {"word1": 10, "word2": 5}; 16 | - После каждого обработанного урла сервер должен вывести статистику: сколько урлов было обработано на данный момент суммарно всеми воркерами; 17 | 18 | `python server.py -w 10 -k 7` (сервер использует 10 воркеров для обкачки и отправляет клиенту топ-7 частых слов) 19 | 20 | Все действия должны быть выделены в классы/функции. 21 | 22 | #### Клиент 23 | Утилита, отправляющая запросы с урлами серверу по TCP в несколько потоков. 24 | Нужно сделать следующее: 25 | 26 | - Подготовить файл с запросами (порядка 100 разных url); 27 | - На вход клиенту передаётся два аргумента --- файл с URL'ами и количество потоков M; 28 | - Клиент создает M потоков, отправляет запросы на сервер в каждом потоке и печатает ответ сервера в стандартый вывод, например: `xxx.com: {'word1': 100, 'word2': 50}`. 29 | 30 | `python client.py 10 urls.txt` 31 | 32 | 33 | Все действия должны быть выделены в классы/функции. 34 | 35 | ### 2. Тесты в отдельном модуле 36 | 37 | ### 3. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 38 | 39 | ### 4. Покрытие тестов через coverage 40 | 41 | ### 5. Зеленый пайплайн в репе 42 | -------------------------------------------------------------------------------- /lesson-03/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #03 (Классы, ООП) 2 | 3 | ### 1. Реализовать класс CustomList наследованием от list 4 | 5 | При этом: 6 | - `CustomList` должен наследоваться от встроенного списка `list` для получения всех методов последнего; 7 | - экземпляры `CustomList` можно складывать и вычитать друг с другом, с обычными списками и с числами: 8 | ```py 9 | CustomList([5, 1, 3, 7]) + CustomList([1, 2, 7]) # CustomList([6, 3, 10, 7]) 10 | CustomList([10]) + [2, 5] # CustomList([12, 5]) 11 | [2, 5] + CustomList([10]) # CustomList([12, 5]) 12 | CustomList([2, 5]) + 10 # CustomList([12, 15]) 13 | 10 + CustomList([2, 5]) # CustomList([12, 15]) 14 | 15 | CustomList([5, 1, 3, 7]) - CustomList([1, 2, 7]) # CustomList([4, -1, -4, 7]) 16 | CustomList([10]) - [2, 5] # CustomList([8, -5]) 17 | [2, 5] - CustomList([10]) # CustomList([-8, 5]) 18 | CustomList([2, 5]) - 10 # CustomList([-8, -5]) 19 | 10 - CustomList([2, 5]) # CustomList([8, 5]) 20 | ``` 21 | Возвращаться должен новый экземпляр `CustomList`, элементы которого будут результатом поэлементного сложения/вычитания элементов исходных списков. 22 | Сложение/вычитание с числом выполняется как сложение/вычитание каждого элемента списка с данным числом; 23 | - при сложении/вычитании списков разной длины отсутствующие элементы меньшего списка считаются нулями; 24 | - после сложения/вычитания исходные списки не должны изменяться; 25 | - при сравнении (`==`, `!=`, `>`, `>=`, `<`, `<=`) экземмпляров CustomList должна сравниваться сумма элементов списков (сравнение с `list` и `int` не нужно); 26 | - должен быть переопределен `str`, чтобы выводились элементы списка и их сумма; 27 | - можно считать элементы списка `CustomList`, `list` и другие операнды всегда всегда целыми числами. 28 | 29 | ### 2. Тесты CustomList в отдельном модуле 30 | 31 | ### 3. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 32 | 33 | ### 4. Покрытие тестов через coverage 34 | 35 | ### 5. Зеленый пайплайн в репе 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deep_python_autumn_2024 2 | Материалы открытого курса Углубленный Python от VK Education, осень 2024 3 | 4 | ## Лекции и материалы (слайды, домашки, код с занятий) 5 | 01. [Введение, типы данных, управляющие конструкции, тестирование](lesson-01) 6 | 02. [Функции](lesson-02) 7 | 03. [Классы, ООП](lesson-03) 8 | 04. [Дескрипторы, метапрограммироование, ABC](lesson-04) 9 | 05. [Стандартная библиотека](lesson-05) 10 | 06. [Потоки, процессы, IPC](lesson-06) 11 | 07. [Асинхронное программирование](lesson-07) 12 | 08. [Память, профилирование](lesson-08) 13 | 09. [Логирование](lesson-09) 14 | 15 | 16 | ## FAQ 17 | * Обязательно ли соблюдение правил оформления репозитория с домашками, как указано в приветственном посте на портале? 18 | > Да. 19 | * Как называть модули с решением? 20 | > Модули с решением должны именоваться исходя из их содержимого, например, `message_predictor.py`, а `task1.py` модуль называть не следует. 21 | * Как называть и располагать тестовые модули? 22 | > Тестовые модули должны именоваться с префиксом `test_` и находиться в корне каталога домашки (01, 02 и тд), для каждой части задания должен быть свой тестовый модуль. 23 | * Как работает мягкий дедлайн? 24 | > Если отправить домашку на проверку до наступления мягкого дедлайна по этой домашке, то можно получить полный балл (7). Более того, вторая и третья попытки, отправленные даже после дедлайна, уже штрафоваться не будут. 25 | * Как отправлять вторую и третью попытки сдачи ДЗ? 26 | > Обязательно нужно переотправить через портал (кнопка "Дополнить" в интерфейсе сдачи), как это выполнялось с первой попыткой. Можно дополнить комментарием в обсуждении, но коментарий не является обязательным. Только комментария недостаточно, тк если случайно его просмотреть, портал будет считать эту домашку проверенной и проверка правок по ней может сильно отсрочиться. 27 | * Списывать нельзя? 28 | > **Списывать нельзя**, но использовать различные ресурсы для подготовки можно. За списывание штраф 3 балла и попытка сдачи данной домашки, то есть можно будет пересдать списанную домашку только с одной попыткой. За повторное списывание студент отчисляется с курса. 29 | 30 | -------------------------------------------------------------------------------- /lesson-04/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #04 (дескрипторы, метаклассы, ABC) 2 | 3 | ### 1. Метакласс, который в начале названий всех атрибутов и методов, кроме магических, добавляет префикс "custom_" 4 | Подменяться должны атрибуты класса и атрибуты экземпляра класса, в том числе добавленные после выполнения конструктора (dynamic в примере). 5 | 6 | ```py 7 | class CustomMeta(...): 8 | pass 9 | 10 | 11 | class CustomClass(metaclass=CustomMeta): 12 | x = 50 13 | 14 | def __init__(self, val=99): 15 | self.val = val 16 | 17 | def line(self): 18 | return 100 19 | 20 | def __str__(self): 21 | return "Custom_by_metaclass" 22 | 23 | 24 | assert CustomClass.custom_x == 50 25 | CustomClass.x # ошибка 26 | 27 | inst = CustomClass() 28 | assert inst.custom_x == 50 29 | assert inst.custom_val == 99 30 | assert inst.custom_line() == 100 31 | assert str(inst) == "Custom_by_metaclass" 32 | 33 | inst.x # ошибка 34 | inst.val # ошибка 35 | inst.line() # ошибка 36 | inst.yyy # ошибка 37 | 38 | inst.dynamic = "added later" 39 | assert inst.custom_dynamic == "added later" 40 | inst.dynamic # ошибка 41 | ``` 42 | 43 | 44 | ### 2. Дескрипторы с проверками типов и значений данных 45 | Нужно сделать три дескриптора для какой-то области интереса (наука, финансы, хобби и тд), но если совсем не получается, то можно использовать шаблона ниже в качестве основы. 46 | У дескрипторов должен быть базовый класс с проверкой, которую наследующие классы должны будут реализовать. 47 | 48 | ```py 49 | class Base...: 50 | pass 51 | 52 | class Integer: 53 | pass 54 | 55 | class String: 56 | pass 57 | 58 | class PositiveInteger: 59 | pass 60 | 61 | class Data: 62 | num = Integer() 63 | name = String() 64 | price = PositiveInteger() 65 | 66 | def __init__(...): 67 | .... 68 | ``` 69 | 70 | 71 | ### 3. Тесты метакласса и дескрипторов 72 | 73 | ### 4. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 74 | 75 | ### 5. Покрытие тестов через coverage 76 | 77 | ### 6. Зеленый пайплайн в репе 78 | -------------------------------------------------------------------------------- /lesson-01/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #01 (введение, тестирование) 2 | 3 | ### 1. Функция оценки сообщения 4 | Реализовать функцию `predict_message_mood`, которая принимает на вход строку `message` и пороги хорошести. 5 | Функция возвращает: 6 | - "неуд", если предсказание модели меньше `bad_threshold`; 7 | - "отл", если предсказание модели больше `good_threshold`; 8 | - "норм" в остальных случаях. 9 | 10 | Функция `predict_message_mood` создает экземпляр класса `SomeModel` и вызывает у этого экземпляра метод `predict` с аргументом `message`. 11 | 12 | ```py 13 | class SomeModel: 14 | def predict(self, message: str) -> float: 15 | # реализация не важна 16 | 17 | 18 | def predict_message_mood( 19 | message: str, 20 | bad_thresholds: float = 0.3, 21 | good_thresholds: float = 0.8, 22 | ) -> str: 23 | ... 24 | model.predict() 25 | ... 26 | 27 | 28 | assert predict_message_mood("Чапаев и пустота") == "отл" 29 | assert predict_message_mood("Чапаев и пустота", 0.8, 0.99) == "норм" 30 | assert predict_message_mood("Вулкан") == "неуд" 31 | ``` 32 | 33 | ### 2. Генератор для чтения и фильтрации файла 34 | Есть текстовый файл, который может не помещаться в память. 35 | В каждой строке файла фраза или предложение: набор слов, разделенных пробелами (знаков препинания нет). 36 | 37 | Генератор должен принимать на вход: 38 | - имя файла или файловый объект; 39 | - список слов для поиска; 40 | - список стоп-слов. 41 | 42 | Генератор перебирает строки файла и возвращает только те из них (строку целиком), где встретилось хотя бы одно из слов для поиска. 43 | Если в одной строке сразу несколько совпадений, то вернуть строку надо лишь один раз. 44 | Если в строке встретилось слово из списка стоп-слов, то такая строка должна игнорирроваться, даже если там есть совпадения по словам поиска. 45 | Поиск совпадений и стоп-слов должен выполняться по полному совпадению слова без учета регистра. 46 | 47 | Например, для строки из файла "а Роза упала на лапу Азора" слово поиска "роза" должно найтись, а "роз" или "розан" - уже нет. 48 | В случае той же строки "а Роза упала на лапу Азора", слова-совпадения "роза" и стоп-слова "азора" исходная строка должна будет быть отброщена. 49 | 50 | ### 3. Тесты в отдельном модуле для каждого пункта 51 | 52 | ### 4. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 53 | 54 | ### 5. Покрытие тестов через coverage 55 | 56 | ### 6. Зеленый пайплайн в репе 57 | -------------------------------------------------------------------------------- /lesson-10/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #10 (Расширения на C) 2 | 3 | ### 1. Реализовать библиотеку для парсинга и сериализации json (с помощью C API) 4 | - Нужно написать модуль custom_json, который имел бы хотя бы два метода: loads и dumps; 5 | - Методу loads на вход подаётся строка в формате JSON. Ограничения: 6 | * JSON-сообщение в виде набор пар ключ-значение (читай как python-словарь); 7 | * Ключём в JSON **всегда** является строка в двойных кавычках; 8 | * Значением может выступать либо число, либо строка. Если захотелось приключений, то можно сделать поддержку и других типов; 9 | * Если входная строка не является JSON-объектом, то выбрасывается исключение 10 | ```C 11 | ... 12 | PyErr_Format(PyExc_TypeError, "Expected object or value"); 13 | return NULL; 14 | ``` 15 | * Возвращаться должен объект типа dict. Например, можно сделать так: 16 | ```C 17 | PyObject *dict = NULL; 18 | if (!(dict = PyDict_New())) { 19 | printf("ERROR: Failed to create Dict Object\n"); 20 | return NULL; 21 | } 22 | 23 | PyObject *key = NULL; 24 | PyObject *value = NULL; 25 | 26 | if (!(key = Py_BuildValue("s", "hello"))) { 27 | printf("ERROR: Failed to build string value\n"); 28 | return NULL; 29 | } 30 | if (!(value = Py_BuildValue("i", 10))) { 31 | printf("ERROR: Failed to build integer value\n"); 32 | return NULL; 33 | } 34 | if (PyDict_SetItem(dict, key, value) < 0) { 35 | printf("ERROR: Failed to set item\n"); 36 | return NULL; 37 | } 38 | if (!(key = Py_BuildValue("s", "world"))) { 39 | printf("ERROR: Failed to build string value\n"); 40 | return NULL; 41 | } 42 | if (!(value = Py_BuildValue("s", "100500"))) { 43 | printf("ERROR: Failed to build string value\n"); 44 | return NULL; 45 | } 46 | if (PyDict_SetItem(dict, key, value) < 0) { 47 | printf("ERROR: Failed to set item\n"); 48 | return NULL; 49 | } 50 | 51 | return dict; 52 | ``` 53 | - Методу dumps в качестве аргумента передаётся объект типа dict и возвращает строку. Ограничения как у loads только наоборот; 54 | 55 | Готовое расширение используется из Python: 56 | ```Python 57 | import json 58 | 59 | import custom_json 60 | 61 | 62 | def main(): 63 | json_str = '{"hello": 10, "world": "value"}' 64 | 65 | json_doc = json.loads(json_str) 66 | cust_json_doc = custom_json.loads(json_str) 67 | 68 | assert json_doc == cust_json_doc 69 | assert json_str == cust_json.dumps(cust_json.loads(json_str)) 70 | 71 | 72 | if __name__ == "__main__": 73 | main() 74 | ``` 75 | 76 | ### 2. Тесты корректности на уровне Python в отдельном модуле 77 | 78 | ### 3. Тесты производительности 79 | Сравнивать скорость работы своей реализации с json на одних и тех же данных. 80 | Данные должны быть большие (как количество JSON, так и размер каждого JSON). Требование: выполнение тестов не менее 100 мс. 81 | 82 | Для генерации тестовых JSON можно использовать статический найденный на просторах интернета JSON. 83 | Можно попробовать использовать библиотеку [Faker](https://faker.readthedocs.io/en/master/) для генерации данных. 84 | Допустимо генерировать рандомные данные. 85 | 86 | ### 4. Зеленый пайплайн в репе 87 | -------------------------------------------------------------------------------- /lesson-10/src/perf.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import time 3 | 4 | import cffi 5 | import fibutils 6 | import fibcyth 7 | 8 | 9 | def fib_rec_py(n: int) -> int: 10 | if n < 3: 11 | return 1 12 | 13 | return fib_rec_py(n - 1) + fib_rec_py(n - 2) 14 | 15 | 16 | def fib_iter_py(n: int) -> int: 17 | a, b = 0, 1 18 | 19 | for _ in range(n): 20 | a, b = b, a + b 21 | 22 | return a 23 | 24 | 25 | def time_native_python(n_rec, n_iter): 26 | start = time.time() 27 | res = fib_rec_py(n_rec) 28 | end = time.time() 29 | print(f"[python] rec fib({n_rec}) = {res}, time = {end - start}") 30 | 31 | start = time.time() 32 | res = fib_iter_py(n_iter) 33 | end = time.time() 34 | print(f"[python] iter fib({n_iter}) = {res}, time = {end - start}") 35 | 36 | 37 | def time_ctypes(n_rec, n_iter): 38 | lib = ctypes.cdll.LoadLibrary("./lib_ctypes/libfibutils.so") 39 | 40 | lib.fib_rec_ctypes.argstype = [ctypes.c_int] 41 | lib.fib_rec_ctypes.restype = ctypes.c_int 42 | 43 | lib.fib_iter_ctypes.argstype = [ctypes.c_int] 44 | lib.fib_iter_ctypes.restype = ctypes.c_int 45 | 46 | start = time.time() 47 | res = lib.fib_rec_ctypes(n_rec) 48 | end = time.time() 49 | print(f"[ctypes] rec fib({n_rec}) = {res}, time = {end - start}") 50 | 51 | start = time.time() 52 | res = lib.fib_iter_ctypes(n_iter) 53 | end = time.time() 54 | print(f"[ctypes] iter fib({n_iter}) = {res}, time = {end - start}") 55 | 56 | 57 | def time_cffi(n_rec, n_iter): 58 | ffi = cffi.FFI() 59 | lib = ffi.dlopen("./lib_ctypes/libfibutils.so") 60 | 61 | ffi.cdef( 62 | "int fib_rec_ctypes(int n);\n" 63 | "int fib_iter_ctypes(int n);\n" 64 | ) 65 | 66 | start = time.time() 67 | res = lib.fib_rec_ctypes(n_rec) 68 | end = time.time() 69 | print(f"[cffi] rec fib({n_rec}) = {res}, time = {end - start}") 70 | 71 | start = time.time() 72 | res = lib.fib_iter_ctypes(n_iter) 73 | end = time.time() 74 | print(f"[cffi] iter fib({n_iter}) = {res}, time = {end - start}") 75 | 76 | 77 | def time_c_api(n_rec, n_iter): 78 | start = time.time() 79 | res = fibutils.fib_rec_capi(n_rec) 80 | end = time.time() 81 | print(f"[c-api] rec fib({n_rec}) = {res}, time = {end - start}") 82 | 83 | start = time.time() 84 | res = fibutils.fib_iter_capi(n_iter) 85 | end = time.time() 86 | print(f"[c-api] iter fib({n_iter}) = {res}, time = {end - start}") 87 | 88 | 89 | def time_cython(n_rec, n_iter): 90 | start = time.time() 91 | res = fibcyth.fib_rec_cy(n_rec) 92 | end = time.time() 93 | print(f"[cython] rec fib({n_rec}) = {res}, time = {end - start}") 94 | 95 | start = time.time() 96 | res = fibcyth.fib_iter_cy(n_iter) 97 | end = time.time() 98 | print(f"[cython] iter fib({n_iter}) = {res}, time = {end - start}") 99 | 100 | 101 | def run(): 102 | n_rec, n_iter = 37, 45 103 | 104 | time_native_python(n_rec, n_iter) 105 | print("-----------\n") 106 | 107 | time_ctypes(n_rec, n_iter) 108 | print("-----------\n") 109 | 110 | time_cffi(n_rec, n_iter) 111 | print("-----------\n") 112 | 113 | time_c_api(n_rec, n_iter) 114 | print("-----------\n") 115 | 116 | time_cython(n_rec, n_iter) 117 | 118 | 119 | if __name__ == "__main__": 120 | run() 121 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 110 | .pdm.toml 111 | .pdm-python 112 | .pdm-build/ 113 | 114 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 115 | __pypackages__/ 116 | 117 | # Celery stuff 118 | celerybeat-schedule 119 | celerybeat.pid 120 | 121 | # SageMath parsed files 122 | *.sage.py 123 | 124 | # Environments 125 | .env 126 | .venv 127 | env/ 128 | venv/ 129 | ENV/ 130 | env.bak/ 131 | venv.bak/ 132 | 133 | # Spyder project settings 134 | .spyderproject 135 | .spyproject 136 | 137 | # Rope project settings 138 | .ropeproject 139 | 140 | # mkdocs documentation 141 | /site 142 | 143 | # mypy 144 | .mypy_cache/ 145 | .dmypy.json 146 | dmypy.json 147 | 148 | # Pyre type checker 149 | .pyre/ 150 | 151 | # pytype static type analyzer 152 | .pytype/ 153 | 154 | # Cython debug symbols 155 | cython_debug/ 156 | 157 | # PyCharm 158 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 159 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 160 | # and can be added to the global gitignore or merged into this file. For a more nuclear 161 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 162 | #.idea/ 163 | -------------------------------------------------------------------------------- /lesson-02/homework.md: -------------------------------------------------------------------------------- 1 | # Домашнее задание #02 (функции) 2 | 3 | ### 1. Функция для обработки json 4 | Функция для обработки должна принимать параметры: 5 | - строку с json; 6 | - список ключей, которые необходимо обработать; 7 | - список токенов, которые нужно найти; 8 | - функцию-обработчик ключа и токена. 9 | 10 | json для задания всегда имеет вид словаря с ключами и значениями из строк. 11 | 12 | Функция парсит строку с json библиотечными средствами. 13 | Для каждого ключа json, который совпадает с одним из переданных ключей для обработки, функция должна искать вхождения токенов в строку-значение по данному ключу. 14 | Для каждого найденного токена должна быть вызвана функция-обработчик с ключом и токеном. 15 | 16 | Поиск ключей должен зависеть от регистра, а поиск токенов должен быть регистронезависимым. 17 | 18 | 19 | ```py 20 | def process_json( 21 | json_str: str, 22 | required_keys: list[str] | None = None, 23 | tokens: list[str] | None = None, 24 | callback: Callable[[str, str], None] | None = None, 25 | ) -> None: 26 | ... 27 | 28 | 29 | # например: 30 | json_str = '{"key1": "Word1 word2", "key2": "word2 word3"}' 31 | required_keys = ["key1", "KEY2"] 32 | tokens = ["WORD1", "word2"] 33 | 34 | process_json(json_str, required_keys, tokens, lambda key, token: f"{key=}, {token=}") 35 | 36 | # выведет: 37 | # key="key1", token="WORD1" 38 | # key="key1", token="word2" 39 | ``` 40 | 41 | ### 2. Параметризуемый декоратор для логирования вызовов и перезапуска функций в случае ошибок 42 | Декоратор `retry_deco` должен: 43 | - принимать опциональными параметрами число перезапусков декорируемой функции и список ожидаемых классов исключений; 44 | - при вызове функции логировать (выводить) название функции, все переданные ей аргументы, номер попытки перезапуска, результат работы функции и ошибку, если было выброшено исключение; 45 | формат логирования произвольный (например, функция и аргументы один раз, а номер попытки и исключение/результат сколько потребуется); 46 | - в случае исключения при выполнении функции декоратор должен выполнить новую попытку запуска функции, пока не достигнет заданного числа перезапусков; 47 | если исключение из списка ожидаемых классов исключений (параметр декоратора), то перезапускать функцию не надо, тк исключения из списка это нормальный режим работы декорируемой функции. 48 | 49 | ```py 50 | def retry_deco(...): 51 | ... 52 | 53 | 54 | @retry_deco(3) 55 | def add(a, b): 56 | return a + b 57 | 58 | 59 | add(4, 2) 60 | # run "add" with positional args = (4, 2), attempt = 1, result = 6 61 | 62 | add(4, b=3) 63 | # run "add" with positional args = (4,), keyword kwargs = {"b": 3}, attempt = 1, result = 7 64 | 65 | 66 | @retry_deco(3) 67 | def check_str(value=None): 68 | if value is None: 69 | raise ValueError() 70 | 71 | return isinstance(value, str) 72 | 73 | 74 | check_str(value="123") 75 | # run "check_str" with keyword kwargs = {"value": "123"}, attempt = 1, result = True 76 | 77 | check_str(value=1) 78 | # run "check_str" with keyword kwargs = {"value": 1}, attempt = 1, result = False 79 | 80 | check_str(value=None) 81 | # run "check_str" with keyword kwargs = {"value": None}, attempt = 1, exception = ValueError 82 | # run "check_str" with keyword kwargs = {"value": None}, attempt = 2, exception = ValueError 83 | # run "check_str" with keyword kwargs = {"value": None}, attempt = 3, exception = ValueError 84 | 85 | 86 | @retry_deco(2, [ValueError]) 87 | def check_int(value=None): 88 | if value is None: 89 | raise ValueError() 90 | 91 | return isinstance(value, int) 92 | 93 | check_int(value=1) 94 | # run "check_int" with keyword kwargs = {"value": 1}, attempt = 1, result = True 95 | 96 | check_int(value=None) 97 | # run "check_int" with keyword kwargs = {"value": None}, attempt = 1, exception = ValueError # нет перезапуска 98 | 99 | ``` 100 | 101 | ### 3. Тесты в отдельном модуле для каждого пункта 102 | 103 | ### 4. Перед отправкой на проверку код должен быть прогнан через flake8 и pylint, по желанию еще black 104 | 105 | ### 5. Покрытие тестов через coverage 106 | 107 | ### 6. Зеленый пайплайн в репе 108 | -------------------------------------------------------------------------------- /lesson-01/test_user.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest import mock 3 | 4 | from user import User 5 | 6 | 7 | class TestUser(unittest.TestCase): 8 | 9 | def test_init(self): 10 | usr = User("steve", 42) 11 | self.assertEqual("steve", usr.name) 12 | self.assertEqual(42, usr.age) 13 | 14 | def test_greetings(self): 15 | usr = User("steve", 42) 16 | self.assertEqual("steve", usr.name) 17 | self.assertEqual("Hello, steve!", usr.greetings()) 18 | 19 | usr = User("", 42) 20 | self.assertEqual("", usr.name) 21 | self.assertEqual("Hello, !", usr.greetings()) 22 | 23 | def test_birthday(self): 24 | usr = User("steve", 42) 25 | self.assertEqual(42, usr.age) 26 | self.assertEqual(43, usr.birthday()) 27 | self.assertEqual(43, usr.age) 28 | 29 | def test_friends_not_impl(self): 30 | usr = User("steve", 42) 31 | 32 | with self.assertRaises(NotImplementedError): 33 | usr.get_friends() 34 | 35 | def test_friends_empty(self): 36 | usr = User("steve", 42) 37 | 38 | with mock.patch("user.fetch_vk_api") as mock_api: 39 | mock_api.return_value = [] 40 | 41 | friends = usr.get_friends() 42 | self.assertEqual([], friends) 43 | 44 | calls = [ 45 | mock.call("/friends", "steve", part=None), 46 | ] 47 | self.assertEqual(calls, mock_api.mock_calls) 48 | 49 | friends = usr.get_friends(name_part="apple") 50 | self.assertEqual([], friends) 51 | 52 | calls = [ 53 | mock.call("/friends", "steve", part=None), 54 | mock.call("/friends", "steve", part="APPLE"), 55 | ] 56 | self.assertEqual(calls, mock_api.mock_calls) 57 | 58 | def test_friends_single(self): 59 | usr = User("steve", 42) 60 | 61 | with mock.patch("user.fetch_vk_api") as mock_api: 62 | mock_api.side_effect = [["voz"], ["voz", "lisa"]] 63 | 64 | friends = usr.get_friends() 65 | self.assertEqual(["voz"], friends) 66 | 67 | calls = [ 68 | mock.call("/friends", "steve", part=None), 69 | ] 70 | self.assertEqual(calls, mock_api.mock_calls) 71 | 72 | friends = usr.get_friends("is") 73 | self.assertEqual(["lisa"], friends) 74 | 75 | calls = [ 76 | mock.call("/friends", "steve", part=None), 77 | mock.call("/friends", "steve", part="IS"), 78 | ] 79 | self.assertEqual(calls, mock_api.mock_calls) 80 | 81 | # friends = usr.get_friends("is") 82 | 83 | @mock.patch("user.fetch_vk_api") 84 | def test_friends_no_filter(self, mock_api): 85 | usr = User("steve", 42) 86 | 87 | def get_friends(*_, **__): 88 | return ["voz", "lisa"] 89 | 90 | mock_api.side_effect = get_friends 91 | 92 | friends = usr.get_friends() 93 | self.assertEqual(["voz", "lisa"], friends) 94 | 95 | calls = [ 96 | mock.call("/friends", "steve", part=None), 97 | ] 98 | self.assertEqual(calls, mock_api.mock_calls) 99 | 100 | friends = usr.get_friends() 101 | self.assertEqual(["voz", "lisa"], friends) 102 | 103 | calls = [ 104 | mock.call("/friends", "steve", part=None), 105 | mock.call("/friends", "steve", part=None), 106 | ] 107 | self.assertEqual(calls, mock_api.mock_calls) 108 | 109 | @mock.patch("user.fetch_vk_api") 110 | def test_friends_connection_error(self, mock_api): 111 | usr = User("steve", 42) 112 | 113 | mock_api.side_effect = Exception("connection error") 114 | 115 | with self.assertRaises(Exception) as err: 116 | usr.get_friends() 117 | self.assertEqual("connection error", str(err.exception)) 118 | 119 | calls = [ 120 | mock.call("/friends", "steve", part=None), 121 | ] 122 | self.assertEqual(calls, mock_api.mock_calls) 123 | 124 | with self.assertRaises(Exception) as err: 125 | usr.get_friends("is") 126 | self.assertEqual("connection error", str(err.exception)) 127 | 128 | calls = [ 129 | mock.call("/friends", "steve", part=None), 130 | mock.call("/friends", "steve", part="IS"), 131 | ] 132 | self.assertEqual(calls, mock_api.mock_calls) 133 | -------------------------------------------------------------------------------- /lesson-11/check_hints.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | from typing import Callable, Generator, Iterable, NewType, Sequence, TypeVar 3 | 4 | DEBUG = True 5 | 6 | UserDataDict = dict[str, str | int] 7 | 8 | Celsius = NewType("Celsius", float) 9 | Fareng = NewType("Fareng", float) 10 | 11 | 12 | def convert_cels_to_faren(temp: Celsius) -> Fareng: 13 | return Fareng(temp * 9 / 5 + 32) 14 | 15 | 16 | def get_max_temp(temps: Iterable[Celsius]) -> Celsius | None: 17 | if temps: 18 | return max(temps) 19 | return None 20 | 21 | 22 | def get_first_temp(temps: Sequence[Celsius]) -> Celsius | None: 23 | if temps: 24 | return temps[0] 25 | return None 26 | 27 | 28 | TempT = TypeVar("TempT") 29 | 30 | def get_first_temp_generic(temps: Sequence[TempT]) -> TempT | None: 31 | if temps: 32 | return temps[0] 33 | return None 34 | 35 | 36 | def gen_temps(delta: float) -> Generator[Celsius, None, str]: 37 | yield Celsius(7.0) 38 | yield Celsius(7.0 + delta) 39 | yield Celsius(7.0 + 2 * delta) 40 | 41 | return "end" # StopIteration("end") 42 | 43 | 44 | def run_temperatures() -> None: 45 | temp = Celsius(30.0) 46 | print(f"{isinstance(temp, float)=}, {type(temp)=}") 47 | 48 | temp_faren = convert_cels_to_faren(temp) 49 | print(f"{temp_faren=}, {type(temp_faren)=}") 50 | 51 | max_temp = get_max_temp( 52 | [Celsius(9.0), Celsius(1.0), Celsius(15.0)] 53 | ) 54 | print(f"{max_temp=}") 55 | 56 | max_temp = get_max_temp( 57 | (Celsius(9.0), Celsius(1.0), Celsius(15.0)) 58 | ) 59 | print(f"{max_temp=}") 60 | 61 | max_temp = get_max_temp( 62 | gen_temps(19.0) 63 | ) 64 | print(f"{max_temp=}") 65 | 66 | # first temp 67 | first_temp = get_first_temp( 68 | [Celsius(9.0), Celsius(1.0), Celsius(15.0)] 69 | ) 70 | print(f"{first_temp=}") 71 | 72 | first_temp = get_first_temp( 73 | (Celsius(9.0), Celsius(1.0), Celsius(15.0)) 74 | ) 75 | print(f"{first_temp=}") 76 | 77 | # first_temp = get_first_temp( 78 | # gen_temps(19.0) 79 | # ) 80 | # print(f"{first_temp=}") 81 | 82 | # TempT 83 | res1 = get_first_temp_generic( 84 | [Celsius(9.0), Celsius(1.0), Celsius(15.0)] 85 | ) 86 | print(f"{res1=}") 87 | 88 | input_tuple: tuple[int,...] = (1, 2, 3) 89 | res2 = get_first_temp_generic( 90 | input_tuple 91 | ) 92 | print(f"{res2=}") 93 | 94 | res3 = get_first_temp_generic( 95 | [Fareng(9.0), Fareng(1.0), Fareng(15.0)] 96 | ) 97 | print(f"{res3=}") 98 | 99 | 100 | 101 | @dataclasses.dataclass 102 | class User: 103 | user_id: int 104 | name: str 105 | 106 | 107 | def make_request(url: str) -> UserDataDict: 108 | # make real http request 109 | return { 110 | "name": "Steve", 111 | "id": 654, 112 | } 113 | 114 | 115 | def fetch_user_data(user: User) -> UserDataDict: 116 | if DEBUG: 117 | url = "https://python.org/123" 118 | else: 119 | url = "https://python.org/{user.user_id}" 120 | 121 | result = make_request(url) 122 | 123 | return result 124 | 125 | 126 | def run_fetch() -> None: 127 | usr = User(456, "Steve") 128 | 129 | user_data: UserDataDict = fetch_user_data(usr) 130 | print(f"{user_data=}") 131 | 132 | 133 | T = TypeVar("T") 134 | M = TypeVar("M") 135 | 136 | def add(x: T, y: M) -> tuple[M, T]: 137 | return (y, x) 138 | 139 | 140 | def add_str(a: str, b: str) -> str: 141 | return a + b 142 | 143 | 144 | def add_int(a: int, b: int) -> int: 145 | return a + b 146 | 147 | 148 | def apply_operation( 149 | fn: Callable[[T, T], T], 150 | op1: T, 151 | op2: T, 152 | ) -> T: 153 | return fn(op1, op2) 154 | 155 | 156 | def deco(fn: Callable[..., T]) -> Callable[..., T]: 157 | def inner(*args, **kwargs) -> T: 158 | return fn(*args, **kwargs) 159 | return inner 160 | 161 | 162 | @deco 163 | def for_deco(name: str) -> User: 164 | return User(123, name) 165 | 166 | 167 | def deco_wrong(fn: Callable[..., T]) -> Callable[..., T]: 168 | def inner(*args, **kwargs) -> T: 169 | return fn(*args, **kwargs), 170 | return inner 171 | 172 | 173 | @deco_wrong 174 | def for_deco_invalid(name: str) -> User: 175 | return User(123, name) 176 | 177 | 178 | def run_functions() -> None: 179 | res = add("1", 99) 180 | print(f"{res=}") 181 | 182 | res1: tuple[int, str] = add("1", 99) 183 | print(f"{res1=}") 184 | 185 | res2: tuple[list, dict] = add({}, []) 186 | print(f"{res2=}") 187 | 188 | # apply 189 | res_add_str = apply_operation(add_str, "qw", "35") 190 | print(f"{res_add_str=}") 191 | 192 | res_add_int = apply_operation(add_int, 35, 12) 193 | print(f"{res_add_int=}") 194 | 195 | res_add = apply_operation(add, "35", 12) 196 | print(f"{res_add=}") 197 | 198 | 199 | if __name__ == "__main__": 200 | run_fetch() 201 | run_temperatures() 202 | run_functions() 203 | 204 | -------------------------------------------------------------------------------- /lesson-10/src/lib_cffi/tmp_mult.c: -------------------------------------------------------------------------------- 1 | #define _CFFI_ 2 | 3 | /* We try to define Py_LIMITED_API before including Python.h. 4 | 5 | Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and 6 | Py_REF_DEBUG are not defined. This is a best-effort approximation: 7 | we can learn about Py_DEBUG from pyconfig.h, but it is unclear if 8 | the same works for the other two macros. Py_DEBUG implies them, 9 | but not the other way around. 10 | 11 | The implementation is messy (issue #350): on Windows, with _MSC_VER, 12 | we have to define Py_LIMITED_API even before including pyconfig.h. 13 | In that case, we guess what pyconfig.h will do to the macros above, 14 | and check our guess after the #include. 15 | 16 | Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv 17 | version >= 16.0.0. With older versions of either, you don't get a 18 | copy of PYTHON3.DLL in the virtualenv. We can't check the version of 19 | CPython *before* we even include pyconfig.h. ffi.set_source() puts 20 | a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is 21 | running on Windows < 3.5, as an attempt at fixing it, but that's 22 | arguably wrong because it may not be the target version of Python. 23 | Still better than nothing I guess. As another workaround, you can 24 | remove the definition of Py_LIMITED_API here. 25 | 26 | See also 'py_limited_api' in cffi/setuptools_ext.py. 27 | */ 28 | #if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) 29 | # ifdef _MSC_VER 30 | # if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) 31 | # define Py_LIMITED_API 32 | # endif 33 | # include 34 | /* sanity-check: Py_LIMITED_API will cause crashes if any of these 35 | are also defined. Normally, the Python file PC/pyconfig.h does not 36 | cause any of these to be defined, with the exception that _DEBUG 37 | causes Py_DEBUG. Double-check that. */ 38 | # ifdef Py_LIMITED_API 39 | # if defined(Py_DEBUG) 40 | # error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" 41 | # endif 42 | # if defined(Py_TRACE_REFS) 43 | # error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" 44 | # endif 45 | # if defined(Py_REF_DEBUG) 46 | # error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" 47 | # endif 48 | # endif 49 | # else 50 | # include 51 | # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) 52 | # define Py_LIMITED_API 53 | # endif 54 | # endif 55 | #endif 56 | 57 | #include 58 | #ifdef __cplusplus 59 | extern "C" { 60 | #endif 61 | #include 62 | 63 | /* This part is from file 'cffi/parse_c_type.h'. It is copied at the 64 | beginning of C sources generated by CFFI's ffi.set_source(). */ 65 | 66 | typedef void *_cffi_opcode_t; 67 | 68 | #define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) 69 | #define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) 70 | #define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) 71 | 72 | #define _CFFI_OP_PRIMITIVE 1 73 | #define _CFFI_OP_POINTER 3 74 | #define _CFFI_OP_ARRAY 5 75 | #define _CFFI_OP_OPEN_ARRAY 7 76 | #define _CFFI_OP_STRUCT_UNION 9 77 | #define _CFFI_OP_ENUM 11 78 | #define _CFFI_OP_FUNCTION 13 79 | #define _CFFI_OP_FUNCTION_END 15 80 | #define _CFFI_OP_NOOP 17 81 | #define _CFFI_OP_BITFIELD 19 82 | #define _CFFI_OP_TYPENAME 21 83 | #define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs 84 | #define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs 85 | #define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) 86 | #define _CFFI_OP_CONSTANT 29 87 | #define _CFFI_OP_CONSTANT_INT 31 88 | #define _CFFI_OP_GLOBAL_VAR 33 89 | #define _CFFI_OP_DLOPEN_FUNC 35 90 | #define _CFFI_OP_DLOPEN_CONST 37 91 | #define _CFFI_OP_GLOBAL_VAR_F 39 92 | #define _CFFI_OP_EXTERN_PYTHON 41 93 | 94 | #define _CFFI_PRIM_VOID 0 95 | #define _CFFI_PRIM_BOOL 1 96 | #define _CFFI_PRIM_CHAR 2 97 | #define _CFFI_PRIM_SCHAR 3 98 | #define _CFFI_PRIM_UCHAR 4 99 | #define _CFFI_PRIM_SHORT 5 100 | #define _CFFI_PRIM_USHORT 6 101 | #define _CFFI_PRIM_INT 7 102 | #define _CFFI_PRIM_UINT 8 103 | #define _CFFI_PRIM_LONG 9 104 | #define _CFFI_PRIM_ULONG 10 105 | #define _CFFI_PRIM_LONGLONG 11 106 | #define _CFFI_PRIM_ULONGLONG 12 107 | #define _CFFI_PRIM_FLOAT 13 108 | #define _CFFI_PRIM_DOUBLE 14 109 | #define _CFFI_PRIM_LONGDOUBLE 15 110 | 111 | #define _CFFI_PRIM_WCHAR 16 112 | #define _CFFI_PRIM_INT8 17 113 | #define _CFFI_PRIM_UINT8 18 114 | #define _CFFI_PRIM_INT16 19 115 | #define _CFFI_PRIM_UINT16 20 116 | #define _CFFI_PRIM_INT32 21 117 | #define _CFFI_PRIM_UINT32 22 118 | #define _CFFI_PRIM_INT64 23 119 | #define _CFFI_PRIM_UINT64 24 120 | #define _CFFI_PRIM_INTPTR 25 121 | #define _CFFI_PRIM_UINTPTR 26 122 | #define _CFFI_PRIM_PTRDIFF 27 123 | #define _CFFI_PRIM_SIZE 28 124 | #define _CFFI_PRIM_SSIZE 29 125 | #define _CFFI_PRIM_INT_LEAST8 30 126 | #define _CFFI_PRIM_UINT_LEAST8 31 127 | #define _CFFI_PRIM_INT_LEAST16 32 128 | #define _CFFI_PRIM_UINT_LEAST16 33 129 | #define _CFFI_PRIM_INT_LEAST32 34 130 | #define _CFFI_PRIM_UINT_LEAST32 35 131 | #define _CFFI_PRIM_INT_LEAST64 36 132 | #define _CFFI_PRIM_UINT_LEAST64 37 133 | #define _CFFI_PRIM_INT_FAST8 38 134 | #define _CFFI_PRIM_UINT_FAST8 39 135 | #define _CFFI_PRIM_INT_FAST16 40 136 | #define _CFFI_PRIM_UINT_FAST16 41 137 | #define _CFFI_PRIM_INT_FAST32 42 138 | #define _CFFI_PRIM_UINT_FAST32 43 139 | #define _CFFI_PRIM_INT_FAST64 44 140 | #define _CFFI_PRIM_UINT_FAST64 45 141 | #define _CFFI_PRIM_INTMAX 46 142 | #define _CFFI_PRIM_UINTMAX 47 143 | #define _CFFI_PRIM_FLOATCOMPLEX 48 144 | #define _CFFI_PRIM_DOUBLECOMPLEX 49 145 | #define _CFFI_PRIM_CHAR16 50 146 | #define _CFFI_PRIM_CHAR32 51 147 | 148 | #define _CFFI__NUM_PRIM 52 149 | #define _CFFI__UNKNOWN_PRIM (-1) 150 | #define _CFFI__UNKNOWN_FLOAT_PRIM (-2) 151 | #define _CFFI__UNKNOWN_LONG_DOUBLE (-3) 152 | 153 | #define _CFFI__IO_FILE_STRUCT (-1) 154 | 155 | 156 | struct _cffi_global_s { 157 | const char *name; 158 | void *address; 159 | _cffi_opcode_t type_op; 160 | void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown 161 | // OP_CPYTHON_BLTN_*: addr of direct function 162 | }; 163 | 164 | struct _cffi_getconst_s { 165 | unsigned long long value; 166 | const struct _cffi_type_context_s *ctx; 167 | int gindex; 168 | }; 169 | 170 | struct _cffi_struct_union_s { 171 | const char *name; 172 | int type_index; // -> _cffi_types, on a OP_STRUCT_UNION 173 | int flags; // _CFFI_F_* flags below 174 | size_t size; 175 | int alignment; 176 | int first_field_index; // -> _cffi_fields array 177 | int num_fields; 178 | }; 179 | #define _CFFI_F_UNION 0x01 // is a union, not a struct 180 | #define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the 181 | // "standard layout" or if some are missing 182 | #define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct 183 | #define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() 184 | #define _CFFI_F_OPAQUE 0x10 // opaque 185 | 186 | struct _cffi_field_s { 187 | const char *name; 188 | size_t field_offset; 189 | size_t field_size; 190 | _cffi_opcode_t field_type_op; 191 | }; 192 | 193 | struct _cffi_enum_s { 194 | const char *name; 195 | int type_index; // -> _cffi_types, on a OP_ENUM 196 | int type_prim; // _CFFI_PRIM_xxx 197 | const char *enumerators; // comma-delimited string 198 | }; 199 | 200 | struct _cffi_typename_s { 201 | const char *name; 202 | int type_index; /* if opaque, points to a possibly artificial 203 | OP_STRUCT which is itself opaque */ 204 | }; 205 | 206 | struct _cffi_type_context_s { 207 | _cffi_opcode_t *types; 208 | const struct _cffi_global_s *globals; 209 | const struct _cffi_field_s *fields; 210 | const struct _cffi_struct_union_s *struct_unions; 211 | const struct _cffi_enum_s *enums; 212 | const struct _cffi_typename_s *typenames; 213 | int num_globals; 214 | int num_struct_unions; 215 | int num_enums; 216 | int num_typenames; 217 | const char *const *includes; 218 | int num_types; 219 | int flags; /* future extension */ 220 | }; 221 | 222 | struct _cffi_parse_info_s { 223 | const struct _cffi_type_context_s *ctx; 224 | _cffi_opcode_t *output; 225 | unsigned int output_size; 226 | size_t error_location; 227 | const char *error_message; 228 | }; 229 | 230 | struct _cffi_externpy_s { 231 | const char *name; 232 | size_t size_of_result; 233 | void *reserved1, *reserved2; 234 | }; 235 | 236 | #ifdef _CFFI_INTERNAL 237 | static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); 238 | static int search_in_globals(const struct _cffi_type_context_s *ctx, 239 | const char *search, size_t search_len); 240 | static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, 241 | const char *search, size_t search_len); 242 | #endif 243 | 244 | /* this block of #ifs should be kept exactly identical between 245 | c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py 246 | and cffi/_cffi_include.h */ 247 | #if defined(_MSC_VER) 248 | # include /* for alloca() */ 249 | # if _MSC_VER < 1600 /* MSVC < 2010 */ 250 | typedef __int8 int8_t; 251 | typedef __int16 int16_t; 252 | typedef __int32 int32_t; 253 | typedef __int64 int64_t; 254 | typedef unsigned __int8 uint8_t; 255 | typedef unsigned __int16 uint16_t; 256 | typedef unsigned __int32 uint32_t; 257 | typedef unsigned __int64 uint64_t; 258 | typedef __int8 int_least8_t; 259 | typedef __int16 int_least16_t; 260 | typedef __int32 int_least32_t; 261 | typedef __int64 int_least64_t; 262 | typedef unsigned __int8 uint_least8_t; 263 | typedef unsigned __int16 uint_least16_t; 264 | typedef unsigned __int32 uint_least32_t; 265 | typedef unsigned __int64 uint_least64_t; 266 | typedef __int8 int_fast8_t; 267 | typedef __int16 int_fast16_t; 268 | typedef __int32 int_fast32_t; 269 | typedef __int64 int_fast64_t; 270 | typedef unsigned __int8 uint_fast8_t; 271 | typedef unsigned __int16 uint_fast16_t; 272 | typedef unsigned __int32 uint_fast32_t; 273 | typedef unsigned __int64 uint_fast64_t; 274 | typedef __int64 intmax_t; 275 | typedef unsigned __int64 uintmax_t; 276 | # else 277 | # include 278 | # endif 279 | # if _MSC_VER < 1800 /* MSVC < 2013 */ 280 | # ifndef __cplusplus 281 | typedef unsigned char _Bool; 282 | # endif 283 | # endif 284 | # define _cffi_float_complex_t _Fcomplex /* include for it */ 285 | # define _cffi_double_complex_t _Dcomplex /* include for it */ 286 | #else 287 | # include 288 | # if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) 289 | # include 290 | # endif 291 | # define _cffi_float_complex_t float _Complex 292 | # define _cffi_double_complex_t double _Complex 293 | #endif 294 | 295 | #ifdef __GNUC__ 296 | # define _CFFI_UNUSED_FN __attribute__((unused)) 297 | #else 298 | # define _CFFI_UNUSED_FN /* nothing */ 299 | #endif 300 | 301 | #ifdef __cplusplus 302 | # ifndef _Bool 303 | typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ 304 | # endif 305 | #endif 306 | 307 | /********** CPython-specific section **********/ 308 | #ifndef PYPY_VERSION 309 | 310 | 311 | #if PY_MAJOR_VERSION >= 3 312 | # define PyInt_FromLong PyLong_FromLong 313 | #endif 314 | 315 | #define _cffi_from_c_double PyFloat_FromDouble 316 | #define _cffi_from_c_float PyFloat_FromDouble 317 | #define _cffi_from_c_long PyInt_FromLong 318 | #define _cffi_from_c_ulong PyLong_FromUnsignedLong 319 | #define _cffi_from_c_longlong PyLong_FromLongLong 320 | #define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong 321 | #define _cffi_from_c__Bool PyBool_FromLong 322 | 323 | #define _cffi_to_c_double PyFloat_AsDouble 324 | #define _cffi_to_c_float PyFloat_AsDouble 325 | 326 | #define _cffi_from_c_int(x, type) \ 327 | (((type)-1) > 0 ? /* unsigned */ \ 328 | (sizeof(type) < sizeof(long) ? \ 329 | PyInt_FromLong((long)x) : \ 330 | sizeof(type) == sizeof(long) ? \ 331 | PyLong_FromUnsignedLong((unsigned long)x) : \ 332 | PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ 333 | (sizeof(type) <= sizeof(long) ? \ 334 | PyInt_FromLong((long)x) : \ 335 | PyLong_FromLongLong((long long)x))) 336 | 337 | #define _cffi_to_c_int(o, type) \ 338 | ((type)( \ 339 | sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ 340 | : (type)_cffi_to_c_i8(o)) : \ 341 | sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ 342 | : (type)_cffi_to_c_i16(o)) : \ 343 | sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ 344 | : (type)_cffi_to_c_i32(o)) : \ 345 | sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ 346 | : (type)_cffi_to_c_i64(o)) : \ 347 | (Py_FatalError("unsupported size for type " #type), (type)0))) 348 | 349 | #define _cffi_to_c_i8 \ 350 | ((int(*)(PyObject *))_cffi_exports[1]) 351 | #define _cffi_to_c_u8 \ 352 | ((int(*)(PyObject *))_cffi_exports[2]) 353 | #define _cffi_to_c_i16 \ 354 | ((int(*)(PyObject *))_cffi_exports[3]) 355 | #define _cffi_to_c_u16 \ 356 | ((int(*)(PyObject *))_cffi_exports[4]) 357 | #define _cffi_to_c_i32 \ 358 | ((int(*)(PyObject *))_cffi_exports[5]) 359 | #define _cffi_to_c_u32 \ 360 | ((unsigned int(*)(PyObject *))_cffi_exports[6]) 361 | #define _cffi_to_c_i64 \ 362 | ((long long(*)(PyObject *))_cffi_exports[7]) 363 | #define _cffi_to_c_u64 \ 364 | ((unsigned long long(*)(PyObject *))_cffi_exports[8]) 365 | #define _cffi_to_c_char \ 366 | ((int(*)(PyObject *))_cffi_exports[9]) 367 | #define _cffi_from_c_pointer \ 368 | ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) 369 | #define _cffi_to_c_pointer \ 370 | ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) 371 | #define _cffi_get_struct_layout \ 372 | not used any more 373 | #define _cffi_restore_errno \ 374 | ((void(*)(void))_cffi_exports[13]) 375 | #define _cffi_save_errno \ 376 | ((void(*)(void))_cffi_exports[14]) 377 | #define _cffi_from_c_char \ 378 | ((PyObject *(*)(char))_cffi_exports[15]) 379 | #define _cffi_from_c_deref \ 380 | ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) 381 | #define _cffi_to_c \ 382 | ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) 383 | #define _cffi_from_c_struct \ 384 | ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) 385 | #define _cffi_to_c_wchar_t \ 386 | ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) 387 | #define _cffi_from_c_wchar_t \ 388 | ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) 389 | #define _cffi_to_c_long_double \ 390 | ((long double(*)(PyObject *))_cffi_exports[21]) 391 | #define _cffi_to_c__Bool \ 392 | ((_Bool(*)(PyObject *))_cffi_exports[22]) 393 | #define _cffi_prepare_pointer_call_argument \ 394 | ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ 395 | PyObject *, char **))_cffi_exports[23]) 396 | #define _cffi_convert_array_from_object \ 397 | ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) 398 | #define _CFFI_CPIDX 25 399 | #define _cffi_call_python \ 400 | ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) 401 | #define _cffi_to_c_wchar3216_t \ 402 | ((int(*)(PyObject *))_cffi_exports[26]) 403 | #define _cffi_from_c_wchar3216_t \ 404 | ((PyObject *(*)(int))_cffi_exports[27]) 405 | #define _CFFI_NUM_EXPORTS 28 406 | 407 | struct _cffi_ctypedescr; 408 | 409 | static void *_cffi_exports[_CFFI_NUM_EXPORTS]; 410 | 411 | #define _cffi_type(index) ( \ 412 | assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ 413 | (struct _cffi_ctypedescr *)_cffi_types[index]) 414 | 415 | static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, 416 | const struct _cffi_type_context_s *ctx) 417 | { 418 | PyObject *module, *o_arg, *new_module; 419 | void *raw[] = { 420 | (void *)module_name, 421 | (void *)version, 422 | (void *)_cffi_exports, 423 | (void *)ctx, 424 | }; 425 | 426 | module = PyImport_ImportModule("_cffi_backend"); 427 | if (module == NULL) 428 | goto failure; 429 | 430 | o_arg = PyLong_FromVoidPtr((void *)raw); 431 | if (o_arg == NULL) 432 | goto failure; 433 | 434 | new_module = PyObject_CallMethod( 435 | module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); 436 | 437 | Py_DECREF(o_arg); 438 | Py_DECREF(module); 439 | return new_module; 440 | 441 | failure: 442 | Py_XDECREF(module); 443 | return NULL; 444 | } 445 | 446 | 447 | #ifdef HAVE_WCHAR_H 448 | typedef wchar_t _cffi_wchar_t; 449 | #else 450 | typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ 451 | #endif 452 | 453 | _CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) 454 | { 455 | if (sizeof(_cffi_wchar_t) == 2) 456 | return (uint16_t)_cffi_to_c_wchar_t(o); 457 | else 458 | return (uint16_t)_cffi_to_c_wchar3216_t(o); 459 | } 460 | 461 | _CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) 462 | { 463 | if (sizeof(_cffi_wchar_t) == 2) 464 | return _cffi_from_c_wchar_t((_cffi_wchar_t)x); 465 | else 466 | return _cffi_from_c_wchar3216_t((int)x); 467 | } 468 | 469 | _CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) 470 | { 471 | if (sizeof(_cffi_wchar_t) == 4) 472 | return (int)_cffi_to_c_wchar_t(o); 473 | else 474 | return (int)_cffi_to_c_wchar3216_t(o); 475 | } 476 | 477 | _CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) 478 | { 479 | if (sizeof(_cffi_wchar_t) == 4) 480 | return _cffi_from_c_wchar_t((_cffi_wchar_t)x); 481 | else 482 | return _cffi_from_c_wchar3216_t((int)x); 483 | } 484 | 485 | union _cffi_union_alignment_u { 486 | unsigned char m_char; 487 | unsigned short m_short; 488 | unsigned int m_int; 489 | unsigned long m_long; 490 | unsigned long long m_longlong; 491 | float m_float; 492 | double m_double; 493 | long double m_longdouble; 494 | }; 495 | 496 | struct _cffi_freeme_s { 497 | struct _cffi_freeme_s *next; 498 | union _cffi_union_alignment_u alignment; 499 | }; 500 | 501 | _CFFI_UNUSED_FN static int 502 | _cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, 503 | char **output_data, Py_ssize_t datasize, 504 | struct _cffi_freeme_s **freeme) 505 | { 506 | char *p; 507 | if (datasize < 0) 508 | return -1; 509 | 510 | p = *output_data; 511 | if (p == NULL) { 512 | struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( 513 | offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); 514 | if (fp == NULL) 515 | return -1; 516 | fp->next = *freeme; 517 | *freeme = fp; 518 | p = *output_data = (char *)&fp->alignment; 519 | } 520 | memset((void *)p, 0, (size_t)datasize); 521 | return _cffi_convert_array_from_object(p, ctptr, arg); 522 | } 523 | 524 | _CFFI_UNUSED_FN static void 525 | _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) 526 | { 527 | do { 528 | void *p = (void *)freeme; 529 | freeme = freeme->next; 530 | PyObject_Free(p); 531 | } while (freeme != NULL); 532 | } 533 | 534 | /********** end CPython-specific section **********/ 535 | #else 536 | _CFFI_UNUSED_FN 537 | static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); 538 | # define _cffi_call_python _cffi_call_python_org 539 | #endif 540 | 541 | 542 | #define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) 543 | 544 | #define _cffi_prim_int(size, sign) \ 545 | ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ 546 | (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ 547 | (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ 548 | (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ 549 | _CFFI__UNKNOWN_PRIM) 550 | 551 | #define _cffi_prim_float(size) \ 552 | ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ 553 | (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ 554 | (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ 555 | _CFFI__UNKNOWN_FLOAT_PRIM) 556 | 557 | #define _cffi_check_int(got, got_nonpos, expected) \ 558 | ((got_nonpos) == (expected <= 0) && \ 559 | (got) == (unsigned long long)expected) 560 | 561 | #ifdef MS_WIN32 562 | # define _cffi_stdcall __stdcall 563 | #else 564 | # define _cffi_stdcall /* nothing */ 565 | #endif 566 | 567 | #ifdef __cplusplus 568 | } 569 | #endif 570 | 571 | /************************************************************/ 572 | 573 | 574 | int mult(int a, int b, int c) 575 | { 576 | int res = 0; 577 | res = a * b * c; 578 | return res; 579 | } 580 | 581 | 582 | /************************************************************/ 583 | 584 | static void *_cffi_types[] = { 585 | /* 0 */ _CFFI_OP(_CFFI_OP_FUNCTION, 1), // int()(int, int, int) 586 | /* 1 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 7), // int 587 | /* 2 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 7), 588 | /* 3 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 7), 589 | /* 4 */ _CFFI_OP(_CFFI_OP_FUNCTION_END, 0), 590 | }; 591 | 592 | static int _cffi_d_mult(int x0, int x1, int x2) 593 | { 594 | return mult(x0, x1, x2); 595 | } 596 | #ifndef PYPY_VERSION 597 | static PyObject * 598 | _cffi_f_mult(PyObject *self, PyObject *args) 599 | { 600 | int x0; 601 | int x1; 602 | int x2; 603 | int result; 604 | PyObject *pyresult; 605 | PyObject *arg0; 606 | PyObject *arg1; 607 | PyObject *arg2; 608 | 609 | if (!PyArg_UnpackTuple(args, "mult", 3, 3, &arg0, &arg1, &arg2)) 610 | return NULL; 611 | 612 | x0 = _cffi_to_c_int(arg0, int); 613 | if (x0 == (int)-1 && PyErr_Occurred()) 614 | return NULL; 615 | 616 | x1 = _cffi_to_c_int(arg1, int); 617 | if (x1 == (int)-1 && PyErr_Occurred()) 618 | return NULL; 619 | 620 | x2 = _cffi_to_c_int(arg2, int); 621 | if (x2 == (int)-1 && PyErr_Occurred()) 622 | return NULL; 623 | 624 | Py_BEGIN_ALLOW_THREADS 625 | _cffi_restore_errno(); 626 | { result = mult(x0, x1, x2); } 627 | _cffi_save_errno(); 628 | Py_END_ALLOW_THREADS 629 | 630 | (void)self; /* unused */ 631 | pyresult = _cffi_from_c_int(result, int); 632 | return pyresult; 633 | } 634 | #else 635 | # define _cffi_f_mult _cffi_d_mult 636 | #endif 637 | 638 | static const struct _cffi_global_s _cffi_globals[] = { 639 | { "mult", (void *)_cffi_f_mult, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_V, 0), (void *)_cffi_d_mult }, 640 | }; 641 | 642 | static const struct _cffi_type_context_s _cffi_type_context = { 643 | _cffi_types, 644 | _cffi_globals, 645 | NULL, /* no fields */ 646 | NULL, /* no struct_unions */ 647 | NULL, /* no enums */ 648 | NULL, /* no typenames */ 649 | 1, /* num_globals */ 650 | 0, /* num_struct_unions */ 651 | 0, /* num_enums */ 652 | 0, /* num_typenames */ 653 | NULL, /* no includes */ 654 | 5, /* num_types */ 655 | 0, /* flags */ 656 | }; 657 | 658 | #ifdef __GNUC__ 659 | # pragma GCC visibility push(default) /* for -fvisibility= */ 660 | #endif 661 | 662 | #ifdef PYPY_VERSION 663 | PyMODINIT_FUNC 664 | _cffi_pypyinit_tmp_mult(const void *p[]) 665 | { 666 | p[0] = (const void *)0x2601; 667 | p[1] = &_cffi_type_context; 668 | #if PY_MAJOR_VERSION >= 3 669 | return NULL; 670 | #endif 671 | } 672 | # ifdef _MSC_VER 673 | PyMODINIT_FUNC 674 | # if PY_MAJOR_VERSION >= 3 675 | PyInit_tmp_mult(void) { return NULL; } 676 | # else 677 | inittmp_mult(void) { } 678 | # endif 679 | # endif 680 | #elif PY_MAJOR_VERSION >= 3 681 | PyMODINIT_FUNC 682 | PyInit_tmp_mult(void) 683 | { 684 | return _cffi_init("tmp_mult", 0x2601, &_cffi_type_context); 685 | } 686 | #else 687 | PyMODINIT_FUNC 688 | inittmp_mult(void) 689 | { 690 | _cffi_init("tmp_mult", 0x2601, &_cffi_type_context); 691 | } 692 | #endif 693 | 694 | #ifdef __GNUC__ 695 | # pragma GCC visibility pop 696 | #endif 697 | -------------------------------------------------------------------------------- /lesson-08/class_08.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "2e9acf08-367d-4aa3-bf2c-f3ef2a10fdb1", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import sys" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 10, 16 | "id": "2b00c067-7d0d-4212-a349-c6e7c7bccf41", 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "data": { 21 | "text/plain": [ 22 | "(4294967295, 4294967295)" 23 | ] 24 | }, 25 | "execution_count": 10, 26 | "metadata": {}, 27 | "output_type": "execute_result" 28 | } 29 | ], 30 | "source": [ 31 | "sys.getrefcount(0), sys.getrefcount(1)" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 4, 37 | "id": "c911f6d6-b19c-4e9e-a5bf-1d27d7533b14", 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "data": { 42 | "text/plain": [ 43 | "4294967295" 44 | ] 45 | }, 46 | "execution_count": 4, 47 | "metadata": {}, 48 | "output_type": "execute_result" 49 | } 50 | ], 51 | "source": [ 52 | "x = 1\n", 53 | "sys.getrefcount(x)" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 5, 59 | "id": "777bdb69-5353-48be-b62d-8db1a0bc49ca", 60 | "metadata": {}, 61 | "outputs": [ 62 | { 63 | "data": { 64 | "text/plain": [ 65 | "2" 66 | ] 67 | }, 68 | "execution_count": 5, 69 | "metadata": {}, 70 | "output_type": "execute_result" 71 | } 72 | ], 73 | "source": [ 74 | "sys.getrefcount(10 ** 20)" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 7, 80 | "id": "eeb0eb30-a857-4b53-86fd-22100dc43b77", 81 | "metadata": {}, 82 | "outputs": [ 83 | { 84 | "data": { 85 | "text/plain": [ 86 | "2" 87 | ] 88 | }, 89 | "execution_count": 7, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "x = 10 ** 21\n", 96 | "sys.getrefcount(x)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 9, 102 | "id": "60f29afe-d106-4a75-bbce-1171d746efcb", 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "4294967295" 109 | ] 110 | }, 111 | "execution_count": 9, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "sys.getrefcount(-5)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 10, 123 | "id": "0221c72c-b48e-4e35-a50f-4e8d59214b20", 124 | "metadata": {}, 125 | "outputs": [ 126 | { 127 | "data": { 128 | "text/plain": [ 129 | "2" 130 | ] 131 | }, 132 | "execution_count": 10, 133 | "metadata": {}, 134 | "output_type": "execute_result" 135 | } 136 | ], 137 | "source": [ 138 | "sys.getrefcount(-6)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 3, 144 | "id": "130ea148-ccc2-43c3-b8de-452830ba64ba", 145 | "metadata": {}, 146 | "outputs": [ 147 | { 148 | "data": { 149 | "text/plain": [ 150 | "(4294967295, 3)" 151 | ] 152 | }, 153 | "execution_count": 3, 154 | "metadata": {}, 155 | "output_type": "execute_result" 156 | } 157 | ], 158 | "source": [ 159 | "sys.getrefcount(256), sys.getrefcount(257)" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 4, 165 | "id": "294381ca-9417-45f6-9d26-8d71ba3fa2bb", 166 | "metadata": {}, 167 | "outputs": [], 168 | "source": [ 169 | "s1 = \"qwerty123\"" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 5, 175 | "id": "93191eea-ac7c-44af-aebb-067dbdbf204f", 176 | "metadata": {}, 177 | "outputs": [], 178 | "source": [ 179 | "s2 = \"qwerty123\"" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 6, 185 | "id": "a895e3f4-68b6-4324-b94b-f202dd97f6be", 186 | "metadata": {}, 187 | "outputs": [ 188 | { 189 | "data": { 190 | "text/plain": [ 191 | "True" 192 | ] 193 | }, 194 | "execution_count": 6, 195 | "metadata": {}, 196 | "output_type": "execute_result" 197 | } 198 | ], 199 | "source": [ 200 | "s1 is s2" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 7, 206 | "id": "9d7a2985-8dc5-4e85-b3cf-c336818a9644", 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "s3 = \"qwerty!\"" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 8, 216 | "id": "16216ff2-783c-4e1f-8e29-3c6fbf645b7c", 217 | "metadata": {}, 218 | "outputs": [], 219 | "source": [ 220 | "s4 = \"qwerty!\"" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": 9, 226 | "id": "cabf354d-bb67-4cca-9670-0c2008fe23f5", 227 | "metadata": {}, 228 | "outputs": [ 229 | { 230 | "data": { 231 | "text/plain": [ 232 | "False" 233 | ] 234 | }, 235 | "execution_count": 9, 236 | "metadata": {}, 237 | "output_type": "execute_result" 238 | } 239 | ], 240 | "source": [ 241 | "s3 is s4" 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": null, 247 | "id": "2fa9454f-242f-452e-a703-a169f5a79874", 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": 11, 255 | "id": "0f97f58d-610b-41cf-8343-54c8071a7add", 256 | "metadata": {}, 257 | "outputs": [ 258 | { 259 | "data": { 260 | "text/plain": [ 261 | "4294967295" 262 | ] 263 | }, 264 | "execution_count": 11, 265 | "metadata": {}, 266 | "output_type": "execute_result" 267 | } 268 | ], 269 | "source": [ 270 | "sys.getrefcount(\"qwerty123\")" 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "execution_count": null, 276 | "id": "f96a43b6-8525-48b5-ae07-7f115d04cc60", 277 | "metadata": {}, 278 | "outputs": [], 279 | "source": [] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": null, 284 | "id": "496583ae-fcd0-4a7b-aba0-035b8031f47e", 285 | "metadata": {}, 286 | "outputs": [], 287 | "source": [] 288 | }, 289 | { 290 | "cell_type": "code", 291 | "execution_count": 15, 292 | "id": "65eb6532-9685-439d-a666-869b9a9dcbe9", 293 | "metadata": {}, 294 | "outputs": [ 295 | { 296 | "name": "stdout", 297 | "output_type": "stream", 298 | "text": [ 299 | "1: 2\n", 300 | "2: 3 3\n", 301 | "3: 4 4 4\n", 302 | "4: 3 3\n", 303 | "2: 2\n" 304 | ] 305 | } 306 | ], 307 | "source": [ 308 | "lst1 = [1, 2, 3]\n", 309 | "\n", 310 | "print(\"1:\", sys.getrefcount(lst1))\n", 311 | "\n", 312 | "lst2 = lst1\n", 313 | "\n", 314 | "print(\"2:\", sys.getrefcount(lst1), sys.getrefcount(lst2))\n", 315 | "\n", 316 | "lst3 = lst2\n", 317 | "\n", 318 | "print(\"3:\", sys.getrefcount(lst1), sys.getrefcount(lst2), sys.getrefcount(lst3))\n", 319 | "\n", 320 | "del lst2\n", 321 | "\n", 322 | "print(\"4:\", sys.getrefcount(lst1), sys.getrefcount(lst3))\n", 323 | "\n", 324 | "lst1 = [1, 2, 3]\n", 325 | "\n", 326 | "print(\"2:\", sys.getrefcount(lst3))" 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": 16, 332 | "id": "fa922a41-e056-4881-8f20-92c1bf62e4bb", 333 | "metadata": {}, 334 | "outputs": [ 335 | { 336 | "name": "stdout", 337 | "output_type": "stream", 338 | "text": [ 339 | "1: 2\n", 340 | "sys.getrefcount(obj)=3\n", 341 | "2: 2\n" 342 | ] 343 | } 344 | ], 345 | "source": [ 346 | "lst1 = [1, 2, 3]\n", 347 | "\n", 348 | "def func(obj):\n", 349 | " print(f\"{sys.getrefcount(obj)=}\")\n", 350 | "\n", 351 | "print(\"1:\", sys.getrefcount(lst1))\n", 352 | "\n", 353 | "func(lst1)\n", 354 | "\n", 355 | "print(\"2:\", sys.getrefcount(lst1))" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": null, 361 | "id": "0f30fc83-fb9c-4bbb-ae63-5e00c32f644a", 362 | "metadata": {}, 363 | "outputs": [], 364 | "source": [] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": null, 369 | "id": "91f1571d-df0c-4ae4-a72b-f97af22f2d03", 370 | "metadata": {}, 371 | "outputs": [], 372 | "source": [] 373 | }, 374 | { 375 | "cell_type": "code", 376 | "execution_count": null, 377 | "id": "1f1e739b-e994-4538-891c-d13d4b349887", 378 | "metadata": {}, 379 | "outputs": [], 380 | "source": [] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 23, 385 | "id": "783e54d4-a4e8-42ba-827d-c050976e3d02", 386 | "metadata": {}, 387 | "outputs": [], 388 | "source": [ 389 | "class Animal:\n", 390 | " def __init__(self, name, food):\n", 391 | " self.name = name\n", 392 | " self.food = food\n", 393 | "\n", 394 | " def __str__(self):\n", 395 | " return f\"Animal({self.name}, {self.food}, {id(self)})\"\n", 396 | "\n", 397 | " def __del__(self):\n", 398 | " print(f\"del {str(self)=}\")" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": 24, 404 | "id": "0dda2079-8ad6-4033-8f2b-b0f8b897a6cd", 405 | "metadata": {}, 406 | "outputs": [ 407 | { 408 | "name": "stdout", 409 | "output_type": "stream", 410 | "text": [ 411 | "2\n" 412 | ] 413 | } 414 | ], 415 | "source": [ 416 | "tiger = Animal(\"tiger\", \"meat\")\n", 417 | "print(sys.getrefcount(tiger))" 418 | ] 419 | }, 420 | { 421 | "cell_type": "code", 422 | "execution_count": 25, 423 | "id": "b6fc84a1-37bf-47cb-a708-e37c352d92e0", 424 | "metadata": {}, 425 | "outputs": [ 426 | { 427 | "name": "stdout", 428 | "output_type": "stream", 429 | "text": [ 430 | "del str(self)='Animal(tiger, meat, 4497236784)'\n" 431 | ] 432 | } 433 | ], 434 | "source": [ 435 | "del tiger" 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": 26, 441 | "id": "70fda6f0-246f-499e-a4ca-6451ac1e64e6", 442 | "metadata": {}, 443 | "outputs": [ 444 | { 445 | "name": "stdout", 446 | "output_type": "stream", 447 | "text": [ 448 | "3 3\n" 449 | ] 450 | } 451 | ], 452 | "source": [ 453 | "tiger = Animal(\"tiger\", \"meat\")\n", 454 | "rat = Animal(\"rat\", tiger)\n", 455 | "\n", 456 | "tiger.food = rat\n", 457 | "\n", 458 | "print(sys.getrefcount(tiger), sys.getrefcount(rat))" 459 | ] 460 | }, 461 | { 462 | "cell_type": "code", 463 | "execution_count": 27, 464 | "id": "38ffab64-19fc-403d-bf09-84d09bff242c", 465 | "metadata": {}, 466 | "outputs": [], 467 | "source": [ 468 | "del tiger\n", 469 | "del rat" 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": null, 475 | "id": "48f9ce47-7d63-4d29-9bd6-4c425cb22a43", 476 | "metadata": {}, 477 | "outputs": [], 478 | "source": [] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": null, 483 | "id": "1b5c25d0-2cfe-420b-933d-6b4e915eebbd", 484 | "metadata": {}, 485 | "outputs": [], 486 | "source": [] 487 | }, 488 | { 489 | "cell_type": "code", 490 | "execution_count": null, 491 | "id": "9d4543a5-07b6-472e-88f8-ced209feafe5", 492 | "metadata": {}, 493 | "outputs": [], 494 | "source": [] 495 | }, 496 | { 497 | "cell_type": "code", 498 | "execution_count": null, 499 | "id": "81be1d01-52c6-4e6a-802d-1c88b24aa9c7", 500 | "metadata": {}, 501 | "outputs": [], 502 | "source": [] 503 | }, 504 | { 505 | "cell_type": "code", 506 | "execution_count": 39, 507 | "id": "50646cda-3116-4d44-b506-51ca2fe44d0a", 508 | "metadata": {}, 509 | "outputs": [ 510 | { 511 | "name": "stdout", 512 | "output_type": "stream", 513 | "text": [ 514 | "3 3\n" 515 | ] 516 | } 517 | ], 518 | "source": [ 519 | "class Animal:\n", 520 | " def __init__(self, name, food):\n", 521 | " self.name = name\n", 522 | " self.food = food\n", 523 | "\n", 524 | " def __str__(self):\n", 525 | " return f\"Animal({self.name}, {id(self)})\"\n", 526 | "\n", 527 | " def __del__(self):\n", 528 | " print(f\"del {str(self)=}\")\n", 529 | "\n", 530 | "\n", 531 | "tiger = Animal(\"tiger\", \"meat\")\n", 532 | "rat = Animal(\"rat\", tiger)\n", 533 | "\n", 534 | "tiger.food = rat\n", 535 | "\n", 536 | "print(sys.getrefcount(tiger), sys.getrefcount(rat))" 537 | ] 538 | }, 539 | { 540 | "cell_type": "code", 541 | "execution_count": 41, 542 | "id": "737c20fc-8a04-4388-b9e0-9a076139974c", 543 | "metadata": {}, 544 | "outputs": [], 545 | "source": [ 546 | "del tiger\n", 547 | "del rat" 548 | ] 549 | }, 550 | { 551 | "cell_type": "code", 552 | "execution_count": null, 553 | "id": "9f54c6b6-52da-4a8c-bc00-9c10c927b882", 554 | "metadata": {}, 555 | "outputs": [], 556 | "source": [] 557 | }, 558 | { 559 | "cell_type": "code", 560 | "execution_count": 28, 561 | "id": "5516efdd-100b-4074-92af-6d37da02a15c", 562 | "metadata": {}, 563 | "outputs": [], 564 | "source": [ 565 | "import gc" 566 | ] 567 | }, 568 | { 569 | "cell_type": "code", 570 | "execution_count": 42, 571 | "id": "1a87d8ff-e84b-4b20-8a32-3230a4b9c4bd", 572 | "metadata": {}, 573 | "outputs": [ 574 | { 575 | "name": "stdout", 576 | "output_type": "stream", 577 | "text": [ 578 | "del str(self)='Animal(tiger, 4489221456)'\n", 579 | "del str(self)='Animal(rat, 4489229088)'\n" 580 | ] 581 | }, 582 | { 583 | "data": { 584 | "text/plain": [ 585 | "2" 586 | ] 587 | }, 588 | "execution_count": 42, 589 | "metadata": {}, 590 | "output_type": "execute_result" 591 | } 592 | ], 593 | "source": [ 594 | "gc.collect()" 595 | ] 596 | }, 597 | { 598 | "cell_type": "code", 599 | "execution_count": null, 600 | "id": "68d5b7f3-2364-4508-86f6-26ec1aec5cb3", 601 | "metadata": {}, 602 | "outputs": [], 603 | "source": [] 604 | }, 605 | { 606 | "cell_type": "code", 607 | "execution_count": 43, 608 | "id": "c1533bc6-30d4-49bd-ad46-b3dc665eb844", 609 | "metadata": {}, 610 | "outputs": [], 611 | "source": [ 612 | "import ctypes" 613 | ] 614 | }, 615 | { 616 | "cell_type": "code", 617 | "execution_count": 45, 618 | "id": "47764999-2f44-4d36-afd2-16763e0401c7", 619 | "metadata": {}, 620 | "outputs": [], 621 | "source": [ 622 | "class PyObject(ctypes.Structure):\n", 623 | " _fields_ = [(\"refcnt\", ctypes.c_long)]" 624 | ] 625 | }, 626 | { 627 | "cell_type": "code", 628 | "execution_count": 46, 629 | "id": "84b0b725-6eac-44b6-884c-65513cb61f67", 630 | "metadata": {}, 631 | "outputs": [ 632 | { 633 | "name": "stdout", 634 | "output_type": "stream", 635 | "text": [ 636 | "3 3\n", 637 | "ADDRESS 1: PyObject.from_address(id_tiger).refcnt=2, PyObject.from_address(id_rat).refcnt=2\n", 638 | "ADDRESS 2: PyObject.from_address(id_tiger).refcnt=1, PyObject.from_address(id_rat).refcnt=1\n" 639 | ] 640 | } 641 | ], 642 | "source": [ 643 | "class Animal:\n", 644 | " def __init__(self, name, food):\n", 645 | " self.name = name\n", 646 | " self.food = food\n", 647 | "\n", 648 | " def __str__(self):\n", 649 | " return f\"Animal({self.name}, {id(self)})\"\n", 650 | "\n", 651 | " def __del__(self):\n", 652 | " print(f\"del {str(self)=}\")\n", 653 | "\n", 654 | "\n", 655 | "tiger = Animal(\"tiger\", \"meat\")\n", 656 | "rat = Animal(\"rat\", tiger)\n", 657 | "\n", 658 | "tiger.food = rat\n", 659 | "\n", 660 | "print(sys.getrefcount(tiger), sys.getrefcount(rat))\n", 661 | "\n", 662 | "id_tiger = id(tiger)\n", 663 | "id_rat = id(rat)\n", 664 | "\n", 665 | "print(f\"ADDRESS 1: {PyObject.from_address(id_tiger).refcnt=}, {PyObject.from_address(id_rat).refcnt=}\")\n", 666 | "\n", 667 | "del tiger\n", 668 | "del rat\n", 669 | "\n", 670 | "print(f\"ADDRESS 2: {PyObject.from_address(id_tiger).refcnt=}, {PyObject.from_address(id_rat).refcnt=}\")" 671 | ] 672 | }, 673 | { 674 | "cell_type": "code", 675 | "execution_count": 47, 676 | "id": "818dc7ed-a732-4c12-9f29-6988524ab45e", 677 | "metadata": {}, 678 | "outputs": [ 679 | { 680 | "name": "stdout", 681 | "output_type": "stream", 682 | "text": [ 683 | "del str(self)='Animal(tiger, 4488575936)'\n", 684 | "del str(self)='Animal(rat, 4493624000)'\n" 685 | ] 686 | }, 687 | { 688 | "data": { 689 | "text/plain": [ 690 | "3307" 691 | ] 692 | }, 693 | "execution_count": 47, 694 | "metadata": {}, 695 | "output_type": "execute_result" 696 | } 697 | ], 698 | "source": [ 699 | "gc.collect()" 700 | ] 701 | }, 702 | { 703 | "cell_type": "code", 704 | "execution_count": 49, 705 | "id": "a06eab29-74d5-40ac-9b32-7f7047f495b5", 706 | "metadata": {}, 707 | "outputs": [ 708 | { 709 | "data": { 710 | "text/plain": [ 711 | "(4488575936, 4493624000)" 712 | ] 713 | }, 714 | "execution_count": 49, 715 | "metadata": {}, 716 | "output_type": "execute_result" 717 | } 718 | ], 719 | "source": [ 720 | "id_tiger, id_rat" 721 | ] 722 | }, 723 | { 724 | "cell_type": "code", 725 | "execution_count": 50, 726 | "id": "fcadc43c-10f9-4ca8-9a9f-7d1acb15b5d2", 727 | "metadata": {}, 728 | "outputs": [ 729 | { 730 | "name": "stdout", 731 | "output_type": "stream", 732 | "text": [ 733 | "ADDRESS 3: PyObject.from_address(id_tiger).refcnt=4453302368, PyObject.from_address(id_rat).refcnt=0\n" 734 | ] 735 | } 736 | ], 737 | "source": [ 738 | "print(f\"ADDRESS 3: {PyObject.from_address(id_tiger).refcnt=}, {PyObject.from_address(id_rat).refcnt=}\")" 739 | ] 740 | }, 741 | { 742 | "cell_type": "code", 743 | "execution_count": null, 744 | "id": "b8e95789-b2fe-44dd-a6d2-e9eb140cd186", 745 | "metadata": {}, 746 | "outputs": [], 747 | "source": [] 748 | }, 749 | { 750 | "cell_type": "code", 751 | "execution_count": null, 752 | "id": "658487de-3994-4d11-8cbc-f4ce3531b4a2", 753 | "metadata": {}, 754 | "outputs": [], 755 | "source": [] 756 | }, 757 | { 758 | "cell_type": "code", 759 | "execution_count": null, 760 | "id": "626f6273-73cd-43cb-8ed2-331c79ba0a3b", 761 | "metadata": {}, 762 | "outputs": [], 763 | "source": [] 764 | }, 765 | { 766 | "cell_type": "code", 767 | "execution_count": 53, 768 | "id": "e389dd61-4cde-4790-aa18-bc2a3e3d4df7", 769 | "metadata": {}, 770 | "outputs": [], 771 | "source": [ 772 | "import weakref" 773 | ] 774 | }, 775 | { 776 | "cell_type": "code", 777 | "execution_count": 60, 778 | "id": "bebea858-4b71-40d1-9415-df4766af4e79", 779 | "metadata": {}, 780 | "outputs": [ 781 | { 782 | "name": "stdout", 783 | "output_type": "stream", 784 | "text": [ 785 | "1: 2\n", 786 | "2: 2\n", 787 | "del str(self)='Animal(dog, 4487461632)'\n", 788 | "3: 3\n", 789 | "del str(self)='Animal(dog, 4487456016)'\n", 790 | "dog stopped\n", 791 | "dog_link=None\n" 792 | ] 793 | } 794 | ], 795 | "source": [ 796 | "dog = Animal(\"dog\", \"meat\")\n", 797 | "print(\"1:\", sys.getrefcount(dog))\n", 798 | "\n", 799 | "weakref.finalize(dog, lambda: print(\"dog stopped\"))\n", 800 | "\n", 801 | "wdog = weakref.ref(dog)\n", 802 | "\n", 803 | "print(\"2:\", sys.getrefcount(dog))\n", 804 | "\n", 805 | "dog_link = wdog()\n", 806 | "print(\"3:\", sys.getrefcount(dog))\n", 807 | "\n", 808 | "del dog, dog_link\n", 809 | "\n", 810 | "dog_link = wdog()\n", 811 | "print(f\"{dog_link=}\")" 812 | ] 813 | }, 814 | { 815 | "cell_type": "code", 816 | "execution_count": null, 817 | "id": "ce2b9bcd-3173-439e-a02b-631b7e7c93e2", 818 | "metadata": {}, 819 | "outputs": [], 820 | "source": [] 821 | }, 822 | { 823 | "cell_type": "code", 824 | "execution_count": null, 825 | "id": "c67a2218-bd52-4a11-8c0e-dbcfd03eaaf4", 826 | "metadata": {}, 827 | "outputs": [], 828 | "source": [] 829 | }, 830 | { 831 | "cell_type": "code", 832 | "execution_count": 61, 833 | "id": "1e3277de-9dc6-437f-949e-381ca5dada74", 834 | "metadata": {}, 835 | "outputs": [], 836 | "source": [ 837 | "class Point:\n", 838 | "\n", 839 | " def __init__(self, x, y):\n", 840 | " self.x = x\n", 841 | " self.y = y\n", 842 | "\n", 843 | "\n", 844 | "class Point2D:\n", 845 | " __slots__ = (\"x\", \"y\")\n", 846 | "\n", 847 | " def __init__(self, x, y):\n", 848 | " self.x = x\n", 849 | " self.y = y" 850 | ] 851 | }, 852 | { 853 | "cell_type": "code", 854 | "execution_count": 62, 855 | "id": "bba33231-3f2d-40d6-9078-74c122f0f212", 856 | "metadata": {}, 857 | "outputs": [], 858 | "source": [ 859 | "p1 = Point(10, 20)\n", 860 | "p2 = Point2D(43, 99)" 861 | ] 862 | }, 863 | { 864 | "cell_type": "code", 865 | "execution_count": 65, 866 | "id": "d0e079b6-5602-44a6-93da-df8dc1e6c582", 867 | "metadata": {}, 868 | "outputs": [ 869 | { 870 | "data": { 871 | "text/plain": [ 872 | "(10, 20, 43, 99)" 873 | ] 874 | }, 875 | "execution_count": 65, 876 | "metadata": {}, 877 | "output_type": "execute_result" 878 | } 879 | ], 880 | "source": [ 881 | "p1.x, p1.y, p2.x, p2.y" 882 | ] 883 | }, 884 | { 885 | "cell_type": "code", 886 | "execution_count": 66, 887 | "id": "c9349400-29f4-4752-825f-97dd3512a136", 888 | "metadata": {}, 889 | "outputs": [], 890 | "source": [ 891 | "p1.x = 40" 892 | ] 893 | }, 894 | { 895 | "cell_type": "code", 896 | "execution_count": 67, 897 | "id": "ab7a070a-ac04-4bb9-9838-32d985e7bf3b", 898 | "metadata": {}, 899 | "outputs": [], 900 | "source": [ 901 | "p2.x = 50" 902 | ] 903 | }, 904 | { 905 | "cell_type": "code", 906 | "execution_count": 68, 907 | "id": "0f00f04f-b38a-43e0-80f2-aa9d5cfe137c", 908 | "metadata": {}, 909 | "outputs": [ 910 | { 911 | "data": { 912 | "text/plain": [ 913 | "(40, 20, 50, 99)" 914 | ] 915 | }, 916 | "execution_count": 68, 917 | "metadata": {}, 918 | "output_type": "execute_result" 919 | } 920 | ], 921 | "source": [ 922 | "p1.x, p1.y, p2.x, p2.y" 923 | ] 924 | }, 925 | { 926 | "cell_type": "code", 927 | "execution_count": 69, 928 | "id": "eeed5fb0-ba2c-45f7-8a01-705e654c4fe6", 929 | "metadata": {}, 930 | "outputs": [], 931 | "source": [ 932 | "p1.z = 512" 933 | ] 934 | }, 935 | { 936 | "cell_type": "code", 937 | "execution_count": 70, 938 | "id": "90daf90e-3efd-48e8-8f8d-518bd5d44e9b", 939 | "metadata": {}, 940 | "outputs": [ 941 | { 942 | "ename": "AttributeError", 943 | "evalue": "'Point2D' object has no attribute 'z'", 944 | "output_type": "error", 945 | "traceback": [ 946 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 947 | "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", 948 | "Cell \u001b[0;32mIn[70], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mp2\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mz\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m512\u001b[39m\n", 949 | "\u001b[0;31mAttributeError\u001b[0m: 'Point2D' object has no attribute 'z'" 950 | ] 951 | } 952 | ], 953 | "source": [ 954 | "p2.z = 512" 955 | ] 956 | }, 957 | { 958 | "cell_type": "code", 959 | "execution_count": 71, 960 | "id": "a768b1a1-9079-4990-b2d8-653e5d2dd199", 961 | "metadata": {}, 962 | "outputs": [], 963 | "source": [ 964 | "del p2.x" 965 | ] 966 | }, 967 | { 968 | "cell_type": "code", 969 | "execution_count": 72, 970 | "id": "c203bb2e-8a5d-4a73-9997-ea0d1c24da81", 971 | "metadata": {}, 972 | "outputs": [], 973 | "source": [ 974 | "p2.x = 77" 975 | ] 976 | }, 977 | { 978 | "cell_type": "code", 979 | "execution_count": null, 980 | "id": "67dcab4c-e855-4d93-a513-85aeb2655fdb", 981 | "metadata": {}, 982 | "outputs": [], 983 | "source": [] 984 | }, 985 | { 986 | "cell_type": "code", 987 | "execution_count": null, 988 | "id": "cdc16ab2-8e73-43d4-bbdf-9019df332440", 989 | "metadata": {}, 990 | "outputs": [], 991 | "source": [] 992 | }, 993 | { 994 | "cell_type": "code", 995 | "execution_count": 80, 996 | "id": "3dd4ea36-56bc-466a-a776-cb606bd3fcc8", 997 | "metadata": {}, 998 | "outputs": [], 999 | "source": [ 1000 | "%%time\n", 1001 | "\n", 1002 | "N = 10_000_000\n", 1003 | "\n", 1004 | "\n", 1005 | "points = [Point(999, 1999) for _ in range(N)]\n", 1006 | "slot_points = [Point2D(999, 1999) for _ in range(N)]" 1007 | ] 1008 | }, 1009 | { 1010 | "cell_type": "code", 1011 | "execution_count": 74, 1012 | "id": "44ee99e1-7e28-4296-9108-9df0c812e19e", 1013 | "metadata": {}, 1014 | "outputs": [], 1015 | "source": [ 1016 | "def process_points(points):\n", 1017 | " for p in points:\n", 1018 | " p.x + p.y\n", 1019 | " p.x = p.y\n", 1020 | " p.y = p.x" 1021 | ] 1022 | }, 1023 | { 1024 | "cell_type": "code", 1025 | "execution_count": 83, 1026 | "id": "9f3571b8-622f-4108-876c-fa8af6b2441c", 1027 | "metadata": {}, 1028 | "outputs": [ 1029 | { 1030 | "name": "stdout", 1031 | "output_type": "stream", 1032 | "text": [ 1033 | "CPU times: user 6.56 s, sys: 502 ms, total: 7.06 s\n", 1034 | "Wall time: 9 s\n" 1035 | ] 1036 | } 1037 | ], 1038 | "source": [ 1039 | "%%time\n", 1040 | "\n", 1041 | "N = 5_000_000\n", 1042 | "\n", 1043 | "points = [Point(999, 1999) for _ in range(N)]\n", 1044 | "\n", 1045 | "process_points(points)" 1046 | ] 1047 | }, 1048 | { 1049 | "cell_type": "code", 1050 | "execution_count": 84, 1051 | "id": "db7738a3-66a9-47fe-8a37-35df4430e3d0", 1052 | "metadata": {}, 1053 | "outputs": [ 1054 | { 1055 | "name": "stdout", 1056 | "output_type": "stream", 1057 | "text": [ 1058 | "CPU times: user 4.69 s, sys: 282 ms, total: 4.98 s\n", 1059 | "Wall time: 6.06 s\n" 1060 | ] 1061 | } 1062 | ], 1063 | "source": [ 1064 | "%%time\n", 1065 | "\n", 1066 | "N = 5_000_000\n", 1067 | "\n", 1068 | "slot_points = [Point2D(999, 1999) for _ in range(N)]\n", 1069 | "\n", 1070 | "process_points(slot_points)" 1071 | ] 1072 | }, 1073 | { 1074 | "cell_type": "code", 1075 | "execution_count": null, 1076 | "id": "fba41aad-1381-43a2-bed3-a6e464715c34", 1077 | "metadata": {}, 1078 | "outputs": [], 1079 | "source": [] 1080 | } 1081 | ], 1082 | "metadata": { 1083 | "kernelspec": { 1084 | "display_name": "Python 3 (ipykernel)", 1085 | "language": "python", 1086 | "name": "python3" 1087 | }, 1088 | "language_info": { 1089 | "codemirror_mode": { 1090 | "name": "ipython", 1091 | "version": 3 1092 | }, 1093 | "file_extension": ".py", 1094 | "mimetype": "text/x-python", 1095 | "name": "python", 1096 | "nbconvert_exporter": "python", 1097 | "pygments_lexer": "ipython3", 1098 | "version": "3.12.5" 1099 | } 1100 | }, 1101 | "nbformat": 4, 1102 | "nbformat_minor": 5 1103 | } 1104 | -------------------------------------------------------------------------------- /lesson-06/class_06.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "id": "22964870-c65e-41e7-81df-077a22be2e9a", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import threading" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 5, 16 | "id": "966aec91-c970-4915-8eda-b5643f66da45", 17 | "metadata": {}, 18 | "outputs": [ 19 | { 20 | "data": { 21 | "text/plain": [ 22 | "8" 23 | ] 24 | }, 25 | "execution_count": 5, 26 | "metadata": {}, 27 | "output_type": "execute_result" 28 | } 29 | ], 30 | "source": [ 31 | "threading.active_count()" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 6, 37 | "id": "46376e78-e6a6-4a32-9118-800eea0308ca", 38 | "metadata": {}, 39 | "outputs": [ 40 | { 41 | "data": { 42 | "text/plain": [ 43 | "[<_MainThread(MainThread, started 4702164480)>,\n", 44 | " ,\n", 45 | " ,\n", 46 | " ,\n", 47 | " ,\n", 48 | " ,\n", 49 | " ,\n", 50 | " ]" 51 | ] 52 | }, 53 | "execution_count": 6, 54 | "metadata": {}, 55 | "output_type": "execute_result" 56 | } 57 | ], 58 | "source": [ 59 | "threading.enumerate()" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 7, 65 | "id": "02c55e35-0e09-42f0-b814-004e6c65ccab", 66 | "metadata": {}, 67 | "outputs": [ 68 | { 69 | "name": "stderr", 70 | "output_type": "stream", 71 | "text": [ 72 | "/var/folders/c1/9wdb7dps2x332c6l1y2hrqkh0000gp/T/ipykernel_31000/2258099811.py:1: DeprecationWarning: activeCount() is deprecated, use active_count() instead\n", 73 | " threading.active_count(), threading.activeCount()\n" 74 | ] 75 | }, 76 | { 77 | "data": { 78 | "text/plain": [ 79 | "(8, 8)" 80 | ] 81 | }, 82 | "execution_count": 7, 83 | "metadata": {}, 84 | "output_type": "execute_result" 85 | } 86 | ], 87 | "source": [ 88 | "threading.active_count(), threading.activeCount()" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 9, 94 | "id": "e28cd382-df6b-4813-8ff6-d964f69c9848", 95 | "metadata": {}, 96 | "outputs": [], 97 | "source": [ 98 | "main = threading.current_thread()" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 10, 104 | "id": "c6f46160-73c8-4c56-8299-6947b84bf7ba", 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "data": { 109 | "text/plain": [ 110 | "<_MainThread(MainThread, started 4702164480)>" 111 | ] 112 | }, 113 | "execution_count": 10, 114 | "metadata": {}, 115 | "output_type": "execute_result" 116 | } 117 | ], 118 | "source": [ 119 | "main" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 11, 125 | "id": "bd68e6df-79d1-4b25-91cb-329dab92fcf3", 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "data": { 130 | "text/plain": [ 131 | "('MainThread', 4702164480, 3325268, False, True)" 132 | ] 133 | }, 134 | "execution_count": 11, 135 | "metadata": {}, 136 | "output_type": "execute_result" 137 | } 138 | ], 139 | "source": [ 140 | "main.name, main.ident, main.native_id, main.daemon, main.is_alive()" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 12, 146 | "id": "7177ccac-c2bb-4d33-9047-f62b05d7f4be", 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "data": { 151 | "text/plain": [ 152 | "(4702164480, 3325268)" 153 | ] 154 | }, 155 | "execution_count": 12, 156 | "metadata": {}, 157 | "output_type": "execute_result" 158 | } 159 | ], 160 | "source": [ 161 | "threading.get_ident(), threading.get_native_id()" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 13, 167 | "id": "eddf22bb-f394-4ad9-8fde-40638c13d610", 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "data": { 172 | "text/plain": [ 173 | "\u001b[0;31mDocstring:\u001b[0m\n", 174 | "get_ident() -> integer\n", 175 | "\n", 176 | "Return a non-zero integer that uniquely identifies the current thread\n", 177 | "amongst other threads that exist simultaneously.\n", 178 | "This may be used to identify per-thread resources.\n", 179 | "Even though on some platforms threads identities may appear to be\n", 180 | "allocated consecutive numbers starting at 1, this behavior should not\n", 181 | "be relied upon, and the number should be seen purely as a magic cookie.\n", 182 | "A thread's identity may be reused for another thread after it exits.\n", 183 | "\u001b[0;31mType:\u001b[0m builtin_function_or_method" 184 | ] 185 | }, 186 | "metadata": {}, 187 | "output_type": "display_data" 188 | } 189 | ], 190 | "source": [ 191 | "threading.get_ident?" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 15, 197 | "id": "4d43e88b-723b-4892-b24a-1b61f3534ff0", 198 | "metadata": {}, 199 | "outputs": [ 200 | { 201 | "data": { 202 | "text/plain": [ 203 | "123145487994880" 204 | ] 205 | }, 206 | "execution_count": 15, 207 | "metadata": {}, 208 | "output_type": "execute_result" 209 | } 210 | ], 211 | "source": [ 212 | "threading.enumerate()[3].ident" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": 16, 218 | "id": "061d754a-9706-4c0e-a691-38725e6a1030", 219 | "metadata": {}, 220 | "outputs": [], 221 | "source": [ 222 | "import time" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 26, 228 | "id": "f593f07c-14a9-4003-b6b4-745678d1b521", 229 | "metadata": {}, 230 | "outputs": [ 231 | { 232 | "name": "stdout", 233 | "output_type": "stream", 234 | "text": [ 235 | "data_th.is_alive()=False\n", 236 | "self.name='Thread-8', self.ident=123145572478976, self.native_id=3411771, self.n=10\n", 237 | "i=0\n", 238 | "i=1\n", 239 | "i=2\n", 240 | "i=3\n" 241 | ] 242 | } 243 | ], 244 | "source": [ 245 | "class DataProcessor(threading.Thread):\n", 246 | " def __init__(self, n):\n", 247 | " super().__init__()\n", 248 | " self.n = n\n", 249 | "\n", 250 | " def run(self):\n", 251 | " print(f\"{self.name=}, {self.ident=}, {self.native_id=}, {self.n=}\")\n", 252 | "\n", 253 | " for i in range(self.n):\n", 254 | " print(f\"{i=}\")\n", 255 | " time.sleep(1)\n", 256 | "\n", 257 | "data_th = DataProcessor(10)\n", 258 | "print(f\"{data_th.is_alive()=}\")\n", 259 | "data_th.start()" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": 19, 265 | "id": "c566ebdf-c829-463e-9849-4f2810c5459e", 266 | "metadata": {}, 267 | "outputs": [ 268 | { 269 | "name": "stdout", 270 | "output_type": "stream", 271 | "text": [ 272 | "121\n", 273 | "i=8\n", 274 | "i=9\n" 275 | ] 276 | } 277 | ], 278 | "source": [ 279 | "print(121)" 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": 27, 285 | "id": "7595fad8-8ce3-44ef-a1e3-780ddfa57651", 286 | "metadata": {}, 287 | "outputs": [ 288 | { 289 | "data": { 290 | "text/plain": [ 291 | "True" 292 | ] 293 | }, 294 | "execution_count": 27, 295 | "metadata": {}, 296 | "output_type": "execute_result" 297 | }, 298 | { 299 | "name": "stdout", 300 | "output_type": "stream", 301 | "text": [ 302 | "i=4\n", 303 | "i=5\n", 304 | "i=6\n", 305 | "i=7\n", 306 | "i=8\n", 307 | "i=9\n" 308 | ] 309 | } 310 | ], 311 | "source": [ 312 | "data_th.is_alive()" 313 | ] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "execution_count": 28, 318 | "id": "8a0aa394-b7f2-4132-8906-4927747ca029", 319 | "metadata": {}, 320 | "outputs": [ 321 | { 322 | "data": { 323 | "text/plain": [ 324 | "False" 325 | ] 326 | }, 327 | "execution_count": 28, 328 | "metadata": {}, 329 | "output_type": "execute_result" 330 | } 331 | ], 332 | "source": [ 333 | "data_th.is_alive()" 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": 33, 339 | "id": "61f9df99-824e-4b46-b848-99927e010e40", 340 | "metadata": {}, 341 | "outputs": [ 342 | { 343 | "name": "stdout", 344 | "output_type": "stream", 345 | "text": [ 346 | "data_th.is_alive()=False\n", 347 | "self.name='Thread-12', self.ident=123145572478976, self.native_id=3415056, self.n=10\n", 348 | "i=0\n", 349 | "i=1\n", 350 | "i=2\n", 351 | "i=3\n", 352 | "i=4\n", 353 | "after join\n", 354 | "i=5\n", 355 | "i=6\n", 356 | "i=7\n", 357 | "i=8\n" 358 | ] 359 | } 360 | ], 361 | "source": [ 362 | "class DataProcessor(threading.Thread):\n", 363 | " def __init__(self, n):\n", 364 | " super().__init__()\n", 365 | " self.n = n\n", 366 | "\n", 367 | " def run(self):\n", 368 | " print(f\"{self.name=}, {self.ident=}, {self.native_id=}, {self.n=}\")\n", 369 | "\n", 370 | " for i in range(self.n):\n", 371 | " print(f\"{i=}\")\n", 372 | " time.sleep(1)\n", 373 | "\n", 374 | "data_th = DataProcessor(10)\n", 375 | "print(f\"{data_th.is_alive()=}\")\n", 376 | "data_th.start()\n", 377 | "data_th.join(timeout=5)\n", 378 | "print(\"after join\")" 379 | ] 380 | }, 381 | { 382 | "cell_type": "code", 383 | "execution_count": null, 384 | "id": "a1d5f653-6160-4333-82ae-e20901fdc619", 385 | "metadata": {}, 386 | "outputs": [], 387 | "source": [] 388 | }, 389 | { 390 | "cell_type": "code", 391 | "execution_count": 39, 392 | "id": "e2064339-ba64-41ee-8f71-40217cce6e4a", 393 | "metadata": {}, 394 | "outputs": [], 395 | "source": [ 396 | "N = 10 ** 8\n", 397 | "\n", 398 | "def counter(a, b):\n", 399 | " while a < b:\n", 400 | " a += 1" 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": 40, 406 | "id": "79e28754-067e-458b-bfb1-aed4bc1aa4ae", 407 | "metadata": {}, 408 | "outputs": [ 409 | { 410 | "name": "stdout", 411 | "output_type": "stream", 412 | "text": [ 413 | "CPU times: user 5.06 s, sys: 90.6 ms, total: 5.15 s\n", 414 | "Wall time: 6.89 s\n" 415 | ] 416 | } 417 | ], 418 | "source": [ 419 | "%%time\n", 420 | "\n", 421 | "counter(0, N)" 422 | ] 423 | }, 424 | { 425 | "cell_type": "code", 426 | "execution_count": 43, 427 | "id": "7e48d44d-123d-4061-a5a4-32fd0ceab0aa", 428 | "metadata": {}, 429 | "outputs": [ 430 | { 431 | "name": "stdout", 432 | "output_type": "stream", 433 | "text": [ 434 | "CPU times: user 5.23 s, sys: 125 ms, total: 5.35 s\n", 435 | "Wall time: 7.33 s\n" 436 | ] 437 | } 438 | ], 439 | "source": [ 440 | "%%time\n", 441 | "\n", 442 | "count_th = threading.Thread(target=counter, args=(0, N))\n", 443 | "count_th.start()\n", 444 | "count_th.join()" 445 | ] 446 | }, 447 | { 448 | "cell_type": "code", 449 | "execution_count": 47, 450 | "id": "6d39730d-f04a-4716-b331-e339727ac82d", 451 | "metadata": {}, 452 | "outputs": [ 453 | { 454 | "name": "stdout", 455 | "output_type": "stream", 456 | "text": [ 457 | "counter_th_0\n", 458 | "counter_th_1\n", 459 | "counter_th_2\n", 460 | "counter_th_3\n", 461 | "counter_th_4\n", 462 | "counter_th_5\n", 463 | "counter_th_6\n", 464 | "counter_th_7\n", 465 | "counter_th_8\n", 466 | "counter_th_9\n", 467 | "CPU times: user 5.39 s, sys: 227 ms, total: 5.62 s\n", 468 | "Wall time: 7.3 s\n" 469 | ] 470 | } 471 | ], 472 | "source": [ 473 | "%%time\n", 474 | "\n", 475 | "N = 10 ** 8\n", 476 | "N_THREADS = 10\n", 477 | "WORK_SIZE = N / N_THREADS\n", 478 | "\n", 479 | "def counter(a, b):\n", 480 | " print(f\"{threading.current_thread().name}\")\n", 481 | " while a < b:\n", 482 | " a += 1\n", 483 | "# 0 - 100\n", 484 | "# 100 - 200\n", 485 | "# ... - N\n", 486 | "\n", 487 | "threads = [\n", 488 | " threading.Thread(\n", 489 | " target=counter,\n", 490 | " args=(i * WORK_SIZE, (i + 1) * WORK_SIZE),\n", 491 | " name=f\"counter_th_{i}\",\n", 492 | " )\n", 493 | " for i in range(N_THREADS)\n", 494 | "]\n", 495 | "for th in threads:\n", 496 | " th.start()\n", 497 | "\n", 498 | "for th in threads:\n", 499 | " th.join()" 500 | ] 501 | }, 502 | { 503 | "cell_type": "code", 504 | "execution_count": null, 505 | "id": "9aeab77f-406b-4644-8843-1ba2eef00f1d", 506 | "metadata": {}, 507 | "outputs": [], 508 | "source": [] 509 | }, 510 | { 511 | "cell_type": "code", 512 | "execution_count": null, 513 | "id": "b8afa76d-1e1a-4a2d-9137-e36c016123c8", 514 | "metadata": {}, 515 | "outputs": [], 516 | "source": [] 517 | }, 518 | { 519 | "cell_type": "code", 520 | "execution_count": 48, 521 | "id": "77a7df64-f82c-4ee6-a50a-f65b512ff0b2", 522 | "metadata": {}, 523 | "outputs": [], 524 | "source": [ 525 | "import sys" 526 | ] 527 | }, 528 | { 529 | "cell_type": "code", 530 | "execution_count": 49, 531 | "id": "8f24d97f-7fad-4243-982e-a1edad83b479", 532 | "metadata": {}, 533 | "outputs": [ 534 | { 535 | "data": { 536 | "text/plain": [ 537 | "0.005" 538 | ] 539 | }, 540 | "execution_count": 49, 541 | "metadata": {}, 542 | "output_type": "execute_result" 543 | } 544 | ], 545 | "source": [ 546 | "sys.getswitchinterval()" 547 | ] 548 | }, 549 | { 550 | "cell_type": "code", 551 | "execution_count": 50, 552 | "id": "7f5f3670-d7f6-4df9-896f-786a8d7fc28a", 553 | "metadata": {}, 554 | "outputs": [ 555 | { 556 | "data": { 557 | "text/plain": [ 558 | "" 559 | ] 560 | }, 561 | "execution_count": 50, 562 | "metadata": {}, 563 | "output_type": "execute_result" 564 | } 565 | ], 566 | "source": [ 567 | "sys.setswitchinterval" 568 | ] 569 | }, 570 | { 571 | "cell_type": "code", 572 | "execution_count": null, 573 | "id": "34d82c22-3c5e-4bae-85ea-8202ec455e91", 574 | "metadata": {}, 575 | "outputs": [], 576 | "source": [] 577 | }, 578 | { 579 | "cell_type": "code", 580 | "execution_count": null, 581 | "id": "31aa584e-8c75-43a7-90cd-e722b3d846b3", 582 | "metadata": {}, 583 | "outputs": [], 584 | "source": [] 585 | }, 586 | { 587 | "cell_type": "code", 588 | "execution_count": 51, 589 | "id": "0615e4e4-a503-4e31-8099-e63b975dd965", 590 | "metadata": {}, 591 | "outputs": [ 592 | { 593 | "name": "stdout", 594 | "output_type": "stream", 595 | "text": [ 596 | "count=0\n", 597 | "counter_th_0\n", 598 | "counter_th_1\n", 599 | "counter_th_2\n", 600 | "counter_th_3\n", 601 | "counter_th_4\n", 602 | "counter_th_5\n", 603 | "counter_th_6\n", 604 | "counter_th_7\n", 605 | "counter_th_8\n", 606 | "counter_th_9\n", 607 | "count=138418\n", 608 | "CPU times: user 3.82 s, sys: 181 ms, total: 4 s\n", 609 | "Wall time: 5.35 s\n" 610 | ] 611 | } 612 | ], 613 | "source": [ 614 | "%%time\n", 615 | "\n", 616 | "N = 10 ** 6\n", 617 | "N_THREADS = 10\n", 618 | "WORK_SIZE = N / N_THREADS\n", 619 | "\n", 620 | "count = 0\n", 621 | "\n", 622 | "\n", 623 | "def counter(a, b):\n", 624 | " print(f\"{threading.current_thread().name}\")\n", 625 | " global count\n", 626 | " \n", 627 | " while a < b:\n", 628 | " tmp = count\n", 629 | " a += 1\n", 630 | " tmp += 1\n", 631 | " lst = list(range(-10, 10))\n", 632 | " y = sorted(lst, key=lambda x: x ** 2)\n", 633 | " count = tmp\n", 634 | "\n", 635 | "\n", 636 | "threads = [\n", 637 | " threading.Thread(\n", 638 | " target=counter,\n", 639 | " args=(i * WORK_SIZE, (i + 1) * WORK_SIZE),\n", 640 | " name=f\"counter_th_{i}\",\n", 641 | " )\n", 642 | " for i in range(N_THREADS)\n", 643 | "]\n", 644 | "\n", 645 | "print(f\"{count=}\")\n", 646 | "\n", 647 | "for th in threads:\n", 648 | " th.start()\n", 649 | "\n", 650 | "for th in threads:\n", 651 | " th.join()\n", 652 | "\n", 653 | "print(f\"{count=}\")" 654 | ] 655 | }, 656 | { 657 | "cell_type": "code", 658 | "execution_count": 52, 659 | "id": "b0688b1e-ddae-40c8-a915-cc319ad28a19", 660 | "metadata": {}, 661 | "outputs": [ 662 | { 663 | "name": "stdout", 664 | "output_type": "stream", 665 | "text": [ 666 | "count=0\n", 667 | "counter_th_0\n", 668 | "counter_th_1\n", 669 | "counter_th_2\n", 670 | "counter_th_3\n", 671 | "counter_th_4\n", 672 | "counter_th_5\n", 673 | "counter_th_6\n", 674 | "counter_th_7\n", 675 | "counter_th_8\n", 676 | "counter_th_9\n", 677 | "count=1000000\n", 678 | "CPU times: user 3.39 s, sys: 200 ms, total: 3.59 s\n", 679 | "Wall time: 4.56 s\n" 680 | ] 681 | } 682 | ], 683 | "source": [ 684 | "\n", 685 | "%%time\n", 686 | "\n", 687 | "N = 10 ** 6\n", 688 | "N_THREADS = 10\n", 689 | "WORK_SIZE = N / N_THREADS\n", 690 | "\n", 691 | "count = 0\n", 692 | "lock = threading.Lock()\n", 693 | "\n", 694 | "\n", 695 | "def counter(a, b):\n", 696 | " print(f\"{threading.current_thread().name}\")\n", 697 | " global count\n", 698 | " \n", 699 | " while a < b:\n", 700 | " lock.acquire()\n", 701 | " tmp = count\n", 702 | " a += 1\n", 703 | " tmp += 1\n", 704 | " lst = list(range(-10, 10))\n", 705 | " y = sorted(lst, key=lambda x: x ** 2)\n", 706 | " count = tmp\n", 707 | " lock.release()\n", 708 | "\n", 709 | "\n", 710 | "threads = [\n", 711 | " threading.Thread(\n", 712 | " target=counter,\n", 713 | " args=(i * WORK_SIZE, (i + 1) * WORK_SIZE),\n", 714 | " name=f\"counter_th_{i}\",\n", 715 | " )\n", 716 | " for i in range(N_THREADS)\n", 717 | "]\n", 718 | "\n", 719 | "print(f\"{count=}\")\n", 720 | "\n", 721 | "for th in threads:\n", 722 | " th.start()\n", 723 | "\n", 724 | "for th in threads:\n", 725 | " th.join()\n", 726 | "\n", 727 | "print(f\"{count=}\")" 728 | ] 729 | }, 730 | { 731 | "cell_type": "code", 732 | "execution_count": null, 733 | "id": "257e70c1-21e0-4397-b912-b0798c70c0ef", 734 | "metadata": {}, 735 | "outputs": [], 736 | "source": [] 737 | }, 738 | { 739 | "cell_type": "code", 740 | "execution_count": null, 741 | "id": "14b17e46-91b6-4c2f-8266-141676dda343", 742 | "metadata": {}, 743 | "outputs": [], 744 | "source": [] 745 | }, 746 | { 747 | "cell_type": "code", 748 | "execution_count": 53, 749 | "id": "eee9299f-5239-4dfa-8747-0d8c6b9c4f8e", 750 | "metadata": {}, 751 | "outputs": [], 752 | "source": [ 753 | "from urllib.request import urlopen" 754 | ] 755 | }, 756 | { 757 | "cell_type": "code", 758 | "execution_count": 54, 759 | "id": "6f3fb7c9-54c8-419a-bd41-69d71527dec2", 760 | "metadata": {}, 761 | "outputs": [], 762 | "source": [ 763 | "def fetch_url(url):\n", 764 | " resp = urlopen(url)\n", 765 | " return resp" 766 | ] 767 | }, 768 | { 769 | "cell_type": "code", 770 | "execution_count": 55, 771 | "id": "92ed0eda-9679-456c-9f81-49034b19fb26", 772 | "metadata": {}, 773 | "outputs": [], 774 | "source": [ 775 | "URL = \"http://ru.wikipedia.org/wiki/Python\"" 776 | ] 777 | }, 778 | { 779 | "cell_type": "code", 780 | "execution_count": 56, 781 | "id": "4ac7fe6c-c707-4026-9ac9-f8b6f0396de2", 782 | "metadata": {}, 783 | "outputs": [], 784 | "source": [ 785 | "resp = fetch_url(URL)" 786 | ] 787 | }, 788 | { 789 | "cell_type": "code", 790 | "execution_count": 60, 791 | "id": "8108b588-af52-4ead-b31e-cfdeffad469a", 792 | "metadata": {}, 793 | "outputs": [ 794 | { 795 | "name": "stdout", 796 | "output_type": "stream", 797 | "text": [ 798 | "CPU times: user 88.4 ms, sys: 29.6 ms, total: 118 ms\n", 799 | "Wall time: 5.92 s\n" 800 | ] 801 | } 802 | ], 803 | "source": [ 804 | "%%time\n", 805 | "\n", 806 | "URL = \"http://ru.wikipedia.org/wiki/Python\"\n", 807 | "URLS = [URL] * 20\n", 808 | "\n", 809 | "\n", 810 | "def fetch_url(url):\n", 811 | " resp = urlopen(url)\n", 812 | " return resp\n", 813 | "\n", 814 | "\n", 815 | "def fetch_batch_urls(urls):\n", 816 | " for url in urls:\n", 817 | " fetch_url(url)\n", 818 | "\n", 819 | "\n", 820 | "fetch_batch_urls(URLS)" 821 | ] 822 | }, 823 | { 824 | "cell_type": "code", 825 | "execution_count": null, 826 | "id": "cfff7334-4006-4bbe-940f-90247d308eb3", 827 | "metadata": {}, 828 | "outputs": [], 829 | "source": [] 830 | }, 831 | { 832 | "cell_type": "code", 833 | "execution_count": 68, 834 | "id": "3dbfe5a5-bf57-459e-9324-bc0e7f9772e2", 835 | "metadata": {}, 836 | "outputs": [ 837 | { 838 | "name": "stdout", 839 | "output_type": "stream", 840 | "text": [ 841 | "fetcher_th_0\n", 842 | "fetcher_th_1\n", 843 | "fetcher_th_2\n", 844 | "fetcher_th_3\n", 845 | "fetcher_th_4\n", 846 | "fetcher_th_5\n", 847 | "fetcher_th_6\n", 848 | "fetcher_th_7\n", 849 | "fetcher_th_8\n", 850 | "fetcher_th_9\n", 851 | "fetcher_th_0, t2 - t1=1.6411490440368652\n", 852 | "fetcher_th_1, t2 - t1=1.6497299671173096\n", 853 | "fetcher_th_3, t2 - t1=1.9293251037597656\n", 854 | "fetcher_th_2, t2 - t1=1.938978910446167\n", 855 | "fetcher_th_4, t2 - t1=2.1756319999694824\n", 856 | "fetcher_th_5, t2 - t1=2.1962778568267822\n", 857 | "fetcher_th_6, t2 - t1=2.43249773979187\n", 858 | "fetcher_th_7, t2 - t1=2.460860013961792\n", 859 | "fetcher_th_8, t2 - t1=2.702885866165161\n", 860 | "fetcher_th_9, t2 - t1=2.754934072494507\n", 861 | "CPU times: user 113 ms, sys: 41.8 ms, total: 155 ms\n", 862 | "Wall time: 2.76 s\n" 863 | ] 864 | } 865 | ], 866 | "source": [ 867 | "%%time\n", 868 | "\n", 869 | "URL = \"http://ru.wikipedia.org/wiki/Python\"\n", 870 | "URLS = [URL] * 20\n", 871 | "N_THREADS = 10\n", 872 | "WORK_SIZE = len(URLS) // N_THREADS\n", 873 | "\n", 874 | "\n", 875 | "def fetch_url(url, sem):\n", 876 | " with sem:\n", 877 | " resp = urlopen(url)\n", 878 | " return resp\n", 879 | "\n", 880 | "\n", 881 | "def fetch_batch_urls(urls, sem):\n", 882 | " print(f\"{threading.current_thread().name}\")\n", 883 | " t1 = time.time()\n", 884 | " for url in urls:\n", 885 | " fetch_url(url, sem)\n", 886 | " t2 = time.time()\n", 887 | " print(f\"{threading.current_thread().name}, {t2 - t1=}\")\n", 888 | "\n", 889 | "\n", 890 | "def run():\n", 891 | " sem = threading.Semaphore(2)\n", 892 | " \n", 893 | " threads = [\n", 894 | " threading.Thread(\n", 895 | " target=fetch_batch_urls,\n", 896 | " args=(URLS[i * WORK_SIZE : (i + 1) * WORK_SIZE], sem),\n", 897 | " name=f\"fetcher_th_{i}\",\n", 898 | " )\n", 899 | " for i in range(N_THREADS)\n", 900 | " ]\n", 901 | " \n", 902 | " for th in threads:\n", 903 | " th.start()\n", 904 | " \n", 905 | " for th in threads:\n", 906 | " th.join()\n", 907 | "\n", 908 | "run()" 909 | ] 910 | }, 911 | { 912 | "cell_type": "code", 913 | "execution_count": 69, 914 | "id": "6cac7b93-b199-4bc3-8328-3d0826a252fa", 915 | "metadata": {}, 916 | "outputs": [], 917 | "source": [ 918 | "import queue" 919 | ] 920 | }, 921 | { 922 | "cell_type": "code", 923 | "execution_count": 72, 924 | "id": "fd1fc599-4470-4d01-ae53-b54bf220d463", 925 | "metadata": {}, 926 | "outputs": [ 927 | { 928 | "name": "stdout", 929 | "output_type": "stream", 930 | "text": [ 931 | "fetcher_th_0fetcher_th_1\n", 932 | "fetcher_th_2\n", 933 | "\n", 934 | "fetcher_th_3\n", 935 | "fetcher_th_4\n", 936 | "fetcher_th_5\n", 937 | "fetcher_th_6\n", 938 | "fetcher_th_7\n", 939 | "fetcher_th_8\n", 940 | "fetcher_th_9\n", 941 | "fetcher_th_8, t2 - t1=12.704658031463623, count=10\n", 942 | "fetcher_th_4, t2 - t1=13.310893774032593, count=9\n", 943 | "fetcher_th_3, t2 - t1=13.319364786148071, count=9\n", 944 | "fetcher_th_2, t2 - t1=13.552070140838623, count=12\n", 945 | "fetcher_th_1, t2 - t1=13.57404112815857, count=11\n", 946 | "fetcher_th_7, t2 - t1=13.817423105239868, count=9\n", 947 | "fetcher_th_6, t2 - t1=13.939372777938843, count=10\n", 948 | "fetcher_th_9, t2 - t1=14.133655071258545, count=9\n", 949 | "fetcher_th_0, t2 - t1=14.198372840881348, count=9\n", 950 | "fetcher_th_5, t2 - t1=14.395900249481201, count=12\n", 951 | "CPU times: user 492 ms, sys: 161 ms, total: 653 ms\n", 952 | "Wall time: 14.4 s\n" 953 | ] 954 | } 955 | ], 956 | "source": [ 957 | "%%time\n", 958 | "\n", 959 | "URL = \"http://ru.wikipedia.org/wiki/Python\"\n", 960 | "URLS = [URL] * 100\n", 961 | "N_THREADS = 10\n", 962 | "WORK_SIZE = len(URLS) // N_THREADS\n", 963 | "\n", 964 | "\n", 965 | "def fetch_url(url, sem):\n", 966 | " with sem:\n", 967 | " resp = urlopen(url)\n", 968 | " return resp\n", 969 | "\n", 970 | "\n", 971 | "def worker_fetch(que, sem):\n", 972 | " print(f\"{threading.current_thread().name}\")\n", 973 | " t1 = time.time()\n", 974 | " count = 0\n", 975 | " while True:\n", 976 | " url = que.get()\n", 977 | " if url is None:\n", 978 | " que.put(url)\n", 979 | " break\n", 980 | "\n", 981 | " count += 1\n", 982 | " fetch_url(url, sem)\n", 983 | "\n", 984 | " t2 = time.time()\n", 985 | " print(f\"{threading.current_thread().name}, {t2 - t1=}, {count=}\")\n", 986 | "\n", 987 | "\n", 988 | "def run():\n", 989 | " sem = threading.Semaphore(2)\n", 990 | " que = queue.Queue()\n", 991 | " for url in URLS:\n", 992 | " que.put(url)\n", 993 | " que.put(None)\n", 994 | " \n", 995 | " threads = [\n", 996 | " threading.Thread(\n", 997 | " target=worker_fetch,\n", 998 | " args=(que, sem),\n", 999 | " name=f\"fetcher_th_{i}\",\n", 1000 | " )\n", 1001 | " for i in range(N_THREADS)\n", 1002 | " ]\n", 1003 | " \n", 1004 | " for th in threads:\n", 1005 | " th.start()\n", 1006 | " \n", 1007 | " for th in threads:\n", 1008 | " th.join()\n", 1009 | "\n", 1010 | "run()" 1011 | ] 1012 | }, 1013 | { 1014 | "cell_type": "code", 1015 | "execution_count": null, 1016 | "id": "00167a22-21a9-48ae-aeb7-0c573cd7bd0d", 1017 | "metadata": {}, 1018 | "outputs": [], 1019 | "source": [] 1020 | }, 1021 | { 1022 | "cell_type": "code", 1023 | "execution_count": null, 1024 | "id": "8d373b78-6f9b-4a01-a53c-b5f55f7d26d7", 1025 | "metadata": {}, 1026 | "outputs": [], 1027 | "source": [] 1028 | }, 1029 | { 1030 | "cell_type": "code", 1031 | "execution_count": 74, 1032 | "id": "87035bd5-eead-4ffe-9db1-329ffd215ed7", 1033 | "metadata": {}, 1034 | "outputs": [ 1035 | { 1036 | "name": "stderr", 1037 | "output_type": "stream", 1038 | "text": [ 1039 | "Exception in thread Thread-18 (bad_data_process):\n", 1040 | "Traceback (most recent call last):\n", 1041 | " File \"/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/threading.py\", line 1075, in _bootstrap_inner\n", 1042 | " self.run()\n", 1043 | " File \"/Users/g.kandaurov/venv_education/vk_py312/lib/python3.12/site-packages/ipykernel/ipkernel.py\", line 766, in run_closure\n", 1044 | " _threading_Thread_run(self)\n", 1045 | " File \"/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/threading.py\", line 1012, in run\n", 1046 | " self._target(*self._args, **self._kwargs)\n", 1047 | " File \"/var/folders/c1/9wdb7dps2x332c6l1y2hrqkh0000gp/T/ipykernel_31000/2875439389.py\", line 3, in bad_data_process\n", 1048 | "Exception: BAD_ERROR\n" 1049 | ] 1050 | }, 1051 | { 1052 | "name": "stdout", 1053 | "output_type": "stream", 1054 | "text": [ 1055 | "start bad\n", 1056 | "finish bad\n" 1057 | ] 1058 | } 1059 | ], 1060 | "source": [ 1061 | "def bad_data_process():\n", 1062 | " print(\"start bad\")\n", 1063 | " raise Exception(\"BAD_ERROR\")\n", 1064 | "\n", 1065 | "\n", 1066 | "th = threading.Thread(target=bad_data_process)\n", 1067 | "th.start()\n", 1068 | "th.join()\n", 1069 | "print(\"finish bad\")" 1070 | ] 1071 | }, 1072 | { 1073 | "cell_type": "code", 1074 | "execution_count": 75, 1075 | "id": "e87468cc-0f48-4141-9627-fae91684e1eb", 1076 | "metadata": {}, 1077 | "outputs": [ 1078 | { 1079 | "name": "stdout", 1080 | "output_type": "stream", 1081 | "text": [ 1082 | "start bad\n", 1083 | "process_error args=(_thread._ExceptHookArgs(exc_type=, exc_value=Exception('BAD_ERROR'), exc_traceback=, thread=),), kwargs={}\n", 1084 | "finish bad\n" 1085 | ] 1086 | } 1087 | ], 1088 | "source": [ 1089 | "def process_error(*args, **kwargs):\n", 1090 | " print(f\"process_error {args=}, {kwargs=}\")\n", 1091 | "\n", 1092 | "threading.excepthook = process_error\n", 1093 | "\n", 1094 | "\n", 1095 | "def bad_data_process():\n", 1096 | " print(\"start bad\")\n", 1097 | " raise Exception(\"BAD_ERROR\")\n", 1098 | "\n", 1099 | "\n", 1100 | "th = threading.Thread(target=bad_data_process)\n", 1101 | "th.start()\n", 1102 | "th.join()\n", 1103 | "print(\"finish bad\")" 1104 | ] 1105 | }, 1106 | { 1107 | "cell_type": "code", 1108 | "execution_count": null, 1109 | "id": "bdeb5d0c-df9f-4177-8ba7-57f4710f88c5", 1110 | "metadata": {}, 1111 | "outputs": [], 1112 | "source": [] 1113 | }, 1114 | { 1115 | "cell_type": "code", 1116 | "execution_count": null, 1117 | "id": "4bdd246f-6537-4e69-80de-71d4501bebd8", 1118 | "metadata": {}, 1119 | "outputs": [], 1120 | "source": [] 1121 | }, 1122 | { 1123 | "cell_type": "code", 1124 | "execution_count": null, 1125 | "id": "7917877c-a497-4687-89e3-be5363857594", 1126 | "metadata": {}, 1127 | "outputs": [], 1128 | "source": [] 1129 | } 1130 | ], 1131 | "metadata": { 1132 | "kernelspec": { 1133 | "display_name": "Python 3 (ipykernel)", 1134 | "language": "python", 1135 | "name": "python3" 1136 | }, 1137 | "language_info": { 1138 | "codemirror_mode": { 1139 | "name": "ipython", 1140 | "version": 3 1141 | }, 1142 | "file_extension": ".py", 1143 | "mimetype": "text/x-python", 1144 | "name": "python", 1145 | "nbconvert_exporter": "python", 1146 | "pygments_lexer": "ipython3", 1147 | "version": "3.12.5" 1148 | } 1149 | }, 1150 | "nbformat": 4, 1151 | "nbformat_minor": 5 1152 | } 1153 | -------------------------------------------------------------------------------- /lesson-01/class_01.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "d7355a71-1f99-4649-b553-261fb89d339d", 6 | "metadata": {}, 7 | "source": [ 8 | "# пример со словарем" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 2, 14 | "id": "53c78dfd-91af-40cf-8cf1-6387bef08659", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "d = {1: 11, 2: 22, 3: 33}" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 3, 24 | "id": "f756ae0a-6d01-4178-81d9-ff6d2d43583b", 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "d[\"str\"] = [1, 2, 3]" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 4, 34 | "id": "0386bc7c-d119-494e-8ca3-505128d5a4e8", 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/plain": [ 40 | "{1: 11, 2: 22, 3: 33, 'str': [1, 2, 3]}" 41 | ] 42 | }, 43 | "execution_count": 4, 44 | "metadata": {}, 45 | "output_type": "execute_result" 46 | } 47 | ], 48 | "source": [ 49 | "d" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 5, 55 | "id": "09b1586b-1f68-4652-ae24-1d9124298d2f", 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "d[(4, 5)] = \"45\"" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 6, 65 | "id": "568f2586-8012-4456-afcf-3ff64b362844", 66 | "metadata": {}, 67 | "outputs": [ 68 | { 69 | "data": { 70 | "text/plain": [ 71 | "{1: 11, 2: 22, 3: 33, 'str': [1, 2, 3], (4, 5): '45'}" 72 | ] 73 | }, 74 | "execution_count": 6, 75 | "metadata": {}, 76 | "output_type": "execute_result" 77 | } 78 | ], 79 | "source": [ 80 | "d" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": 7, 86 | "id": "58f8cc37-657c-445a-8213-57d36d858e41", 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "tup = (4, 5, 10, [11, 12])" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 8, 96 | "id": "adf0dc8e-7e67-463c-9929-856d903f9bd1", 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "ename": "TypeError", 101 | "evalue": "unhashable type: 'list'", 102 | "output_type": "error", 103 | "traceback": [ 104 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 105 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 106 | "Cell \u001b[0;32mIn[8], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43md\u001b[49m\u001b[43m[\u001b[49m\u001b[43mtup\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnew_tup\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", 107 | "\u001b[0;31mTypeError\u001b[0m: unhashable type: 'list'" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "d[tup] = \"new_tup\"" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 10, 118 | "id": "973e3f3c-f79e-45c0-bcfc-9c28d37d6930", 119 | "metadata": {}, 120 | "outputs": [ 121 | { 122 | "ename": "TypeError", 123 | "evalue": "'tuple' object does not support item assignment", 124 | "output_type": "error", 125 | "traceback": [ 126 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 127 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 128 | "Cell \u001b[0;32mIn[10], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mtup\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m\n", 129 | "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "tup[0] = 10" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 12, 140 | "id": "6f11ae4a-983e-4fb2-90c2-ec7253cc95a2", 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "tup[3].append(13)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 13, 150 | "id": "6d40561c-64fd-4ed8-9ff5-d8c6d8e750c8", 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "data": { 155 | "text/plain": [ 156 | "(4, 5, 10, [11, 12, 13])" 157 | ] 158 | }, 159 | "execution_count": 13, 160 | "metadata": {}, 161 | "output_type": "execute_result" 162 | } 163 | ], 164 | "source": [ 165 | "tup" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 16, 171 | "id": "ec158834-718d-4b58-935f-eaec47f1840f", 172 | "metadata": {}, 173 | "outputs": [], 174 | "source": [ 175 | "class User:\n", 176 | " pass\n", 177 | "\n", 178 | "\n", 179 | "class User2:\n", 180 | " 42" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 17, 186 | "id": "28e8fd6c-a723-434b-ae06-181321b985f2", 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "d[User()] = User2()" 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 21, 196 | "id": "7b26d726-a806-4f05-b628-13587edfbb73", 197 | "metadata": {}, 198 | "outputs": [ 199 | { 200 | "data": { 201 | "text/plain": [ 202 | "(286708404, 20, 3307897951569694055)" 203 | ] 204 | }, 205 | "execution_count": 21, 206 | "metadata": {}, 207 | "output_type": "execute_result" 208 | } 209 | ], 210 | "source": [ 211 | "hash(User()), hash(20), hash(\"20\")" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 22, 217 | "id": "66ccd728-74dd-4ba4-9e21-d667573421bc", 218 | "metadata": {}, 219 | "outputs": [ 220 | { 221 | "ename": "TypeError", 222 | "evalue": "unhashable type: 'list'", 223 | "output_type": "error", 224 | "traceback": [ 225 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 226 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 227 | "Cell \u001b[0;32mIn[22], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mhash\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n", 228 | "\u001b[0;31mTypeError\u001b[0m: unhashable type: 'list'" 229 | ] 230 | } 231 | ], 232 | "source": [ 233 | "hash([])" 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": null, 239 | "id": "2d6ee8bd-49f7-4d65-bb2e-504f3952dd1b", 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": null, 247 | "id": "72bb321a-fbca-4c43-8489-f3b5d7ec5da9", 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": null, 255 | "id": "617fc334-6e22-4668-80ec-c259c81eb454", 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "id": "bf8e808d-8100-4eef-9ece-4b343fb11c7e", 263 | "metadata": {}, 264 | "source": [ 265 | "# распаковка enumerate" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": 23, 271 | "id": "521ad178-df50-406f-b0b3-5b7850f80f49", 272 | "metadata": {}, 273 | "outputs": [ 274 | { 275 | "data": { 276 | "text/plain": [ 277 | "{1: 11,\n", 278 | " 2: 22,\n", 279 | " 3: 33,\n", 280 | " 'str': [1, 2, 3],\n", 281 | " (4, 5): '45',\n", 282 | " <__main__.User at 0x1116d1850>: <__main__.User2 at 0x1116d25d0>}" 283 | ] 284 | }, 285 | "execution_count": 23, 286 | "metadata": {}, 287 | "output_type": "execute_result" 288 | } 289 | ], 290 | "source": [ 291 | "d" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 24, 297 | "id": "4dfd84f6-d627-438a-bf02-705cc1b39b04", 298 | "metadata": {}, 299 | "outputs": [ 300 | { 301 | "name": "stdout", 302 | "output_type": "stream", 303 | "text": [ 304 | "1\n", 305 | "2\n", 306 | "3\n", 307 | "str\n", 308 | "(4, 5)\n", 309 | "<__main__.User object at 0x1116d1850>\n" 310 | ] 311 | } 312 | ], 313 | "source": [ 314 | "for x in d:\n", 315 | " print(x)" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 25, 321 | "id": "7c8c393f-273f-4107-a8d7-b0b4cdf2b3d6", 322 | "metadata": {}, 323 | "outputs": [ 324 | { 325 | "name": "stdout", 326 | "output_type": "stream", 327 | "text": [ 328 | "(1, 11)\n", 329 | "(2, 22)\n", 330 | "(3, 33)\n", 331 | "('str', [1, 2, 3])\n", 332 | "((4, 5), '45')\n", 333 | "(<__main__.User object at 0x1116d1850>, <__main__.User2 object at 0x1116d25d0>)\n" 334 | ] 335 | } 336 | ], 337 | "source": [ 338 | "for x in d.items():\n", 339 | " print(x)" 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 26, 345 | "id": "f03119f6-5740-49d6-bb0f-ed1e0775bdb9", 346 | "metadata": {}, 347 | "outputs": [ 348 | { 349 | "name": "stdout", 350 | "output_type": "stream", 351 | "text": [ 352 | "1 11\n", 353 | "2 22\n", 354 | "3 33\n", 355 | "str [1, 2, 3]\n", 356 | "(4, 5) 45\n", 357 | "<__main__.User object at 0x1116d1850> <__main__.User2 object at 0x1116d25d0>\n" 358 | ] 359 | } 360 | ], 361 | "source": [ 362 | "for key, value in d.items():\n", 363 | " print(key, value)" 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": 29, 369 | "id": "d59bf20a-6fe7-4a5d-a2d4-276b6c4f7cff", 370 | "metadata": {}, 371 | "outputs": [ 372 | { 373 | "name": "stdout", 374 | "output_type": "stream", 375 | "text": [ 376 | "i=0, key=1, value=11\n", 377 | "i=1, key=2, value=22\n", 378 | "i=2, key=3, value=33\n", 379 | "i=3, key='str', value=[1, 2, 3]\n", 380 | "i=4, key=(4, 5), value='45'\n", 381 | "i=5, key=<__main__.User object at 0x1116d1850>, value=<__main__.User2 object at 0x1116d25d0>\n" 382 | ] 383 | } 384 | ], 385 | "source": [ 386 | "for i, (key, value) in enumerate(d.items()):\n", 387 | " print(f\"{i=}, {key=}, {value=}\")" 388 | ] 389 | }, 390 | { 391 | "cell_type": "code", 392 | "execution_count": null, 393 | "id": "e8a4d219-a3d3-4ed5-bf71-0ef158007aa8", 394 | "metadata": {}, 395 | "outputs": [], 396 | "source": [] 397 | }, 398 | { 399 | "cell_type": "markdown", 400 | "id": "3a6962ba-02a4-48dd-bd99-a5fbee59e6f7", 401 | "metadata": {}, 402 | "source": [ 403 | "# for для файла" 404 | ] 405 | }, 406 | { 407 | "cell_type": "code", 408 | "execution_count": 36, 409 | "id": "737c7b3d-4230-4189-9bcd-b4a997ae0052", 410 | "metadata": {}, 411 | "outputs": [], 412 | "source": [ 413 | "with open(\"example\", \"w\") as f:\n", 414 | " f.write(\"123\\n456\\n789\")" 415 | ] 416 | }, 417 | { 418 | "cell_type": "code", 419 | "execution_count": 37, 420 | "id": "08d72b5a-e731-46c1-938f-92e6cd928d6d", 421 | "metadata": {}, 422 | "outputs": [ 423 | { 424 | "name": "stdout", 425 | "output_type": "stream", 426 | "text": [ 427 | "123\n", 428 | "456\n", 429 | "789" 430 | ] 431 | } 432 | ], 433 | "source": [ 434 | "!cat example" 435 | ] 436 | }, 437 | { 438 | "cell_type": "code", 439 | "execution_count": 40, 440 | "id": "76cd3747-8b41-4488-a10c-840ccdd511bd", 441 | "metadata": {}, 442 | "outputs": [ 443 | { 444 | "name": "stdout", 445 | "output_type": "stream", 446 | "text": [ 447 | "73\n" 448 | ] 449 | } 450 | ], 451 | "source": [ 452 | "with open(\"example\", \"r\") as f:\n", 453 | " print(f.fileno())\n", 454 | " data = f.read()" 455 | ] 456 | }, 457 | { 458 | "cell_type": "code", 459 | "execution_count": 41, 460 | "id": "26655d05-4961-425c-acd5-d9dfd8f6175e", 461 | "metadata": {}, 462 | "outputs": [ 463 | { 464 | "data": { 465 | "text/plain": [ 466 | "'123\\n456\\n789'" 467 | ] 468 | }, 469 | "execution_count": 41, 470 | "metadata": {}, 471 | "output_type": "execute_result" 472 | } 473 | ], 474 | "source": [ 475 | "data" 476 | ] 477 | }, 478 | { 479 | "cell_type": "code", 480 | "execution_count": 42, 481 | "id": "b42eb62e-d0de-467a-b705-0001240640dc", 482 | "metadata": {}, 483 | "outputs": [ 484 | { 485 | "data": { 486 | "text/plain": [ 487 | "['123\\n', '456\\n', '789']" 488 | ] 489 | }, 490 | "execution_count": 42, 491 | "metadata": {}, 492 | "output_type": "execute_result" 493 | } 494 | ], 495 | "source": [ 496 | "with open(\"example\", \"r\") as f:\n", 497 | " data = f.readlines()\n", 498 | "\n", 499 | "data" 500 | ] 501 | }, 502 | { 503 | "cell_type": "code", 504 | "execution_count": 44, 505 | "id": "7a116fde-01d5-4e90-8921-ee5088521932", 506 | "metadata": {}, 507 | "outputs": [ 508 | { 509 | "name": "stdout", 510 | "output_type": "stream", 511 | "text": [ 512 | "123\n", 513 | "456\n", 514 | "789\n" 515 | ] 516 | } 517 | ], 518 | "source": [ 519 | "with open(\"example\", \"r\") as f:\n", 520 | " for line in f:\n", 521 | " print(line.strip())" 522 | ] 523 | }, 524 | { 525 | "cell_type": "code", 526 | "execution_count": null, 527 | "id": "00cbc1cf-247f-4f7b-bd39-249302d572ed", 528 | "metadata": {}, 529 | "outputs": [], 530 | "source": [] 531 | }, 532 | { 533 | "cell_type": "code", 534 | "execution_count": null, 535 | "id": "4ae31cbd-9ef7-448c-9442-e0db1a9b6306", 536 | "metadata": {}, 537 | "outputs": [], 538 | "source": [] 539 | }, 540 | { 541 | "cell_type": "markdown", 542 | "id": "93634b72-33f8-4907-9ec4-32776428e962", 543 | "metadata": {}, 544 | "source": [ 545 | "# Iterator" 546 | ] 547 | }, 548 | { 549 | "cell_type": "code", 550 | "execution_count": 47, 551 | "id": "03e388f3-eb69-4589-8951-a5964a83f365", 552 | "metadata": {}, 553 | "outputs": [], 554 | "source": [ 555 | "class SpecialIterator:\n", 556 | " def __init__(self, limit):\n", 557 | " self.limit = limit\n", 558 | " self.counter = 0\n", 559 | "\n", 560 | " def __iter__(self):\n", 561 | " print(\"--- iter ----\")\n", 562 | " return self\n", 563 | "\n", 564 | " def __next__(self):\n", 565 | " print(\"next\")\n", 566 | " if self.counter < self.limit:\n", 567 | " self.counter += 1\n", 568 | " return self.counter\n", 569 | " else:\n", 570 | " raise StopIteration" 571 | ] 572 | }, 573 | { 574 | "cell_type": "code", 575 | "execution_count": 48, 576 | "id": "b6c94d53-e369-4341-8114-c56701985036", 577 | "metadata": {}, 578 | "outputs": [ 579 | { 580 | "name": "stdout", 581 | "output_type": "stream", 582 | "text": [ 583 | "--- iter ----\n", 584 | "next\n", 585 | "it=1\n", 586 | "next\n", 587 | "it=2\n", 588 | "next\n", 589 | "it=3\n", 590 | "next\n", 591 | "it=4\n", 592 | "next\n", 593 | "it=5\n", 594 | "next\n" 595 | ] 596 | } 597 | ], 598 | "source": [ 599 | "for it in SpecialIterator(5):\n", 600 | " print(f\"{it=}\")" 601 | ] 602 | }, 603 | { 604 | "cell_type": "code", 605 | "execution_count": 50, 606 | "id": "fc9b665a-de60-4e12-a163-41902cd118e5", 607 | "metadata": {}, 608 | "outputs": [], 609 | "source": [ 610 | "spec = SpecialIterator(3)" 611 | ] 612 | }, 613 | { 614 | "cell_type": "code", 615 | "execution_count": 51, 616 | "id": "6f3b29a0-0df1-4770-95f3-08c7ab574e62", 617 | "metadata": {}, 618 | "outputs": [ 619 | { 620 | "name": "stdout", 621 | "output_type": "stream", 622 | "text": [ 623 | "--- iter ----\n" 624 | ] 625 | } 626 | ], 627 | "source": [ 628 | "it_spec = iter(spec)" 629 | ] 630 | }, 631 | { 632 | "cell_type": "code", 633 | "execution_count": 52, 634 | "id": "5e1035e2-0f44-4ce8-9cdc-e527239d55d3", 635 | "metadata": {}, 636 | "outputs": [ 637 | { 638 | "name": "stdout", 639 | "output_type": "stream", 640 | "text": [ 641 | "next\n" 642 | ] 643 | }, 644 | { 645 | "data": { 646 | "text/plain": [ 647 | "1" 648 | ] 649 | }, 650 | "execution_count": 52, 651 | "metadata": {}, 652 | "output_type": "execute_result" 653 | } 654 | ], 655 | "source": [ 656 | "next(it_spec)" 657 | ] 658 | }, 659 | { 660 | "cell_type": "code", 661 | "execution_count": 53, 662 | "id": "cfdbb716-aa76-46f7-ace9-7bc3ff94d159", 663 | "metadata": {}, 664 | "outputs": [ 665 | { 666 | "name": "stdout", 667 | "output_type": "stream", 668 | "text": [ 669 | "next\n" 670 | ] 671 | }, 672 | { 673 | "data": { 674 | "text/plain": [ 675 | "2" 676 | ] 677 | }, 678 | "execution_count": 53, 679 | "metadata": {}, 680 | "output_type": "execute_result" 681 | } 682 | ], 683 | "source": [ 684 | "next(it_spec)" 685 | ] 686 | }, 687 | { 688 | "cell_type": "code", 689 | "execution_count": 54, 690 | "id": "ce1ba96f-8e28-4acc-ada7-4bae3282296f", 691 | "metadata": {}, 692 | "outputs": [ 693 | { 694 | "name": "stdout", 695 | "output_type": "stream", 696 | "text": [ 697 | "--- iter ----\n" 698 | ] 699 | } 700 | ], 701 | "source": [ 702 | "it_spec_2 = iter(spec)" 703 | ] 704 | }, 705 | { 706 | "cell_type": "code", 707 | "execution_count": 55, 708 | "id": "a43920a5-2f51-4e6f-a691-e494ebc3ca0d", 709 | "metadata": {}, 710 | "outputs": [ 711 | { 712 | "name": "stdout", 713 | "output_type": "stream", 714 | "text": [ 715 | "next\n" 716 | ] 717 | }, 718 | { 719 | "data": { 720 | "text/plain": [ 721 | "3" 722 | ] 723 | }, 724 | "execution_count": 55, 725 | "metadata": {}, 726 | "output_type": "execute_result" 727 | } 728 | ], 729 | "source": [ 730 | "next(it_spec_2)" 731 | ] 732 | }, 733 | { 734 | "cell_type": "code", 735 | "execution_count": 56, 736 | "id": "3ca81324-513f-4444-87d2-51101aa2a0d4", 737 | "metadata": {}, 738 | "outputs": [ 739 | { 740 | "name": "stdout", 741 | "output_type": "stream", 742 | "text": [ 743 | "next\n" 744 | ] 745 | }, 746 | { 747 | "ename": "StopIteration", 748 | "evalue": "", 749 | "output_type": "error", 750 | "traceback": [ 751 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 752 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 753 | "Cell \u001b[0;32mIn[56], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mit_spec_2\u001b[49m\u001b[43m)\u001b[49m\n", 754 | "Cell \u001b[0;32mIn[47], line 16\u001b[0m, in \u001b[0;36mSpecialIterator.__next__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcounter\n\u001b[1;32m 15\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m---> 16\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mStopIteration\u001b[39;00m\n", 755 | "\u001b[0;31mStopIteration\u001b[0m: " 756 | ] 757 | } 758 | ], 759 | "source": [ 760 | "next(it_spec_2)" 761 | ] 762 | }, 763 | { 764 | "cell_type": "code", 765 | "execution_count": 57, 766 | "id": "f1c1b583-60de-4b4d-8ebb-a879dda02260", 767 | "metadata": {}, 768 | "outputs": [], 769 | "source": [ 770 | "class SpecItems:\n", 771 | " def __init__(self):\n", 772 | " self._data = [11, 22, 33]\n", 773 | "\n", 774 | " def __getitem__(self, key):\n", 775 | " return self._data[key]" 776 | ] 777 | }, 778 | { 779 | "cell_type": "code", 780 | "execution_count": 58, 781 | "id": "577a30c0-19cd-4eca-9896-6a59301cfbdb", 782 | "metadata": {}, 783 | "outputs": [], 784 | "source": [ 785 | "spec_items = SpecItems()" 786 | ] 787 | }, 788 | { 789 | "cell_type": "code", 790 | "execution_count": 59, 791 | "id": "98f33a85-dea8-487a-bbbe-7fdc729e3ebc", 792 | "metadata": {}, 793 | "outputs": [ 794 | { 795 | "data": { 796 | "text/plain": [ 797 | "22" 798 | ] 799 | }, 800 | "execution_count": 59, 801 | "metadata": {}, 802 | "output_type": "execute_result" 803 | } 804 | ], 805 | "source": [ 806 | "spec_items[1]" 807 | ] 808 | }, 809 | { 810 | "cell_type": "code", 811 | "execution_count": 60, 812 | "id": "c6831511-1af8-4595-b6f0-8beb963b8bc2", 813 | "metadata": {}, 814 | "outputs": [ 815 | { 816 | "data": { 817 | "text/plain": [ 818 | "[11, 33]" 819 | ] 820 | }, 821 | "execution_count": 60, 822 | "metadata": {}, 823 | "output_type": "execute_result" 824 | } 825 | ], 826 | "source": [ 827 | "spec_items[0::2]" 828 | ] 829 | }, 830 | { 831 | "cell_type": "code", 832 | "execution_count": 61, 833 | "id": "58c04ec9-cfdc-448d-855e-e3c4a0af9ae0", 834 | "metadata": {}, 835 | "outputs": [ 836 | { 837 | "name": "stdout", 838 | "output_type": "stream", 839 | "text": [ 840 | "11\n", 841 | "22\n", 842 | "33\n" 843 | ] 844 | } 845 | ], 846 | "source": [ 847 | "for item in spec_items:\n", 848 | " print(item)" 849 | ] 850 | }, 851 | { 852 | "cell_type": "code", 853 | "execution_count": null, 854 | "id": "1d8d9a12-ff7d-4976-9806-bc29c8bd286b", 855 | "metadata": {}, 856 | "outputs": [], 857 | "source": [] 858 | }, 859 | { 860 | "cell_type": "markdown", 861 | "id": "c6bc5134-2a5d-41ef-a7d9-99e5209646a5", 862 | "metadata": {}, 863 | "source": [ 864 | "# генератор" 865 | ] 866 | }, 867 | { 868 | "cell_type": "code", 869 | "execution_count": 62, 870 | "id": "01b9fdf4-8ba1-42b0-9671-b96f4bc02e62", 871 | "metadata": {}, 872 | "outputs": [], 873 | "source": [ 874 | "def empty_gen():\n", 875 | " print(\"run\")\n", 876 | " if False:\n", 877 | " yield\n", 878 | " return 42\n", 879 | "\n", 880 | "gen = empty_gen()" 881 | ] 882 | }, 883 | { 884 | "cell_type": "code", 885 | "execution_count": 63, 886 | "id": "fc24e4e2-d5c3-4494-ac5c-b33719cb6cb5", 887 | "metadata": {}, 888 | "outputs": [ 889 | { 890 | "data": { 891 | "text/plain": [ 892 | "generator" 893 | ] 894 | }, 895 | "execution_count": 63, 896 | "metadata": {}, 897 | "output_type": "execute_result" 898 | } 899 | ], 900 | "source": [ 901 | "type(gen)" 902 | ] 903 | }, 904 | { 905 | "cell_type": "code", 906 | "execution_count": 65, 907 | "id": "45741f5d-d026-4f0d-a1bf-8379613546ef", 908 | "metadata": {}, 909 | "outputs": [ 910 | { 911 | "name": "stdout", 912 | "output_type": "stream", 913 | "text": [ 914 | "run\n" 915 | ] 916 | }, 917 | { 918 | "ename": "StopIteration", 919 | "evalue": "42", 920 | "output_type": "error", 921 | "traceback": [ 922 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 923 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 924 | "Cell \u001b[0;32mIn[65], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mgen\u001b[49m\u001b[43m)\u001b[49m\n", 925 | "\u001b[0;31mStopIteration\u001b[0m: 42" 926 | ] 927 | } 928 | ], 929 | "source": [ 930 | "next(gen)" 931 | ] 932 | }, 933 | { 934 | "cell_type": "code", 935 | "execution_count": null, 936 | "id": "9aebd548-2090-4ece-8b4c-cc117923dd5a", 937 | "metadata": {}, 938 | "outputs": [], 939 | "source": [] 940 | }, 941 | { 942 | "cell_type": "code", 943 | "execution_count": null, 944 | "id": "482f4c6b-e63f-4cd5-89f0-93e1f241c9b5", 945 | "metadata": {}, 946 | "outputs": [], 947 | "source": [] 948 | }, 949 | { 950 | "cell_type": "code", 951 | "execution_count": 66, 952 | "id": "374166f0-69c6-47fb-afa9-ca42e7599f44", 953 | "metadata": {}, 954 | "outputs": [], 955 | "source": [ 956 | "def gen_step(limit):\n", 957 | " print(\"start\", limit)\n", 958 | "\n", 959 | " count = 0\n", 960 | "\n", 961 | " while count < limit:\n", 962 | " print(\"yield\", count)\n", 963 | " yield count\n", 964 | "\n", 965 | " print(\"after yield\", count)\n", 966 | " count += 1\n", 967 | "\n", 968 | "\n", 969 | "steps = gen_step(3)" 970 | ] 971 | }, 972 | { 973 | "cell_type": "code", 974 | "execution_count": 67, 975 | "id": "39c8624c-545e-4f3a-9ea4-f5baea2e146f", 976 | "metadata": {}, 977 | "outputs": [ 978 | { 979 | "name": "stdout", 980 | "output_type": "stream", 981 | "text": [ 982 | "start 3\n", 983 | "yield 0\n" 984 | ] 985 | }, 986 | { 987 | "data": { 988 | "text/plain": [ 989 | "0" 990 | ] 991 | }, 992 | "execution_count": 67, 993 | "metadata": {}, 994 | "output_type": "execute_result" 995 | } 996 | ], 997 | "source": [ 998 | "next(steps)" 999 | ] 1000 | }, 1001 | { 1002 | "cell_type": "code", 1003 | "execution_count": 68, 1004 | "id": "9ebceb7a-03ce-4eb1-a768-d99097513939", 1005 | "metadata": {}, 1006 | "outputs": [ 1007 | { 1008 | "data": { 1009 | "text/plain": [ 1010 | "" 1011 | ] 1012 | }, 1013 | "execution_count": 68, 1014 | "metadata": {}, 1015 | "output_type": "execute_result" 1016 | } 1017 | ], 1018 | "source": [ 1019 | "steps" 1020 | ] 1021 | }, 1022 | { 1023 | "cell_type": "code", 1024 | "execution_count": 69, 1025 | "id": "ff3b3b1d-d816-4b6b-8200-ed761ef43fa3", 1026 | "metadata": {}, 1027 | "outputs": [ 1028 | { 1029 | "name": "stdout", 1030 | "output_type": "stream", 1031 | "text": [ 1032 | "after yield 0\n", 1033 | "yield 1\n" 1034 | ] 1035 | }, 1036 | { 1037 | "data": { 1038 | "text/plain": [ 1039 | "1" 1040 | ] 1041 | }, 1042 | "execution_count": 69, 1043 | "metadata": {}, 1044 | "output_type": "execute_result" 1045 | } 1046 | ], 1047 | "source": [ 1048 | "next(steps)" 1049 | ] 1050 | }, 1051 | { 1052 | "cell_type": "code", 1053 | "execution_count": 70, 1054 | "id": "be7efece-a1b7-49f5-92fd-6103554767d3", 1055 | "metadata": {}, 1056 | "outputs": [ 1057 | { 1058 | "name": "stdout", 1059 | "output_type": "stream", 1060 | "text": [ 1061 | "after yield 1\n", 1062 | "yield 2\n" 1063 | ] 1064 | }, 1065 | { 1066 | "data": { 1067 | "text/plain": [ 1068 | "2" 1069 | ] 1070 | }, 1071 | "execution_count": 70, 1072 | "metadata": {}, 1073 | "output_type": "execute_result" 1074 | } 1075 | ], 1076 | "source": [ 1077 | "next(steps)" 1078 | ] 1079 | }, 1080 | { 1081 | "cell_type": "code", 1082 | "execution_count": 71, 1083 | "id": "7369265c-a594-43a4-8d3b-d193135df59e", 1084 | "metadata": {}, 1085 | "outputs": [ 1086 | { 1087 | "name": "stdout", 1088 | "output_type": "stream", 1089 | "text": [ 1090 | "after yield 2\n" 1091 | ] 1092 | }, 1093 | { 1094 | "ename": "StopIteration", 1095 | "evalue": "", 1096 | "output_type": "error", 1097 | "traceback": [ 1098 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 1099 | "\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)", 1100 | "Cell \u001b[0;32mIn[71], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43msteps\u001b[49m\u001b[43m)\u001b[49m\n", 1101 | "\u001b[0;31mStopIteration\u001b[0m: " 1102 | ] 1103 | } 1104 | ], 1105 | "source": [ 1106 | "next(steps)" 1107 | ] 1108 | }, 1109 | { 1110 | "cell_type": "code", 1111 | "execution_count": 72, 1112 | "id": "567342d2-5d8f-4009-ad4b-c2baff324afd", 1113 | "metadata": {}, 1114 | "outputs": [ 1115 | { 1116 | "name": "stdout", 1117 | "output_type": "stream", 1118 | "text": [ 1119 | "start 3\n", 1120 | "yield 0\n", 1121 | "0\n", 1122 | "after yield 0\n", 1123 | "yield 1\n", 1124 | "1\n", 1125 | "after yield 1\n", 1126 | "yield 2\n", 1127 | "2\n", 1128 | "after yield 2\n" 1129 | ] 1130 | } 1131 | ], 1132 | "source": [ 1133 | "for item in gen_step(3):\n", 1134 | " print(item)" 1135 | ] 1136 | }, 1137 | { 1138 | "cell_type": "code", 1139 | "execution_count": 73, 1140 | "id": "4f2962dc-009e-415a-92c9-bdefba4e48a6", 1141 | "metadata": {}, 1142 | "outputs": [], 1143 | "source": [ 1144 | "it = iter([1, 2, 3, 4, 5])" 1145 | ] 1146 | }, 1147 | { 1148 | "cell_type": "code", 1149 | "execution_count": 74, 1150 | "id": "937de8b4-91c6-4ffa-a2a0-c87d0e0f4ccc", 1151 | "metadata": {}, 1152 | "outputs": [ 1153 | { 1154 | "name": "stdout", 1155 | "output_type": "stream", 1156 | "text": [ 1157 | "\n" 1158 | ] 1159 | } 1160 | ], 1161 | "source": [ 1162 | "print(it)" 1163 | ] 1164 | }, 1165 | { 1166 | "cell_type": "code", 1167 | "execution_count": 75, 1168 | "id": "8811984f-35a0-42b2-976a-9219e62e1511", 1169 | "metadata": {}, 1170 | "outputs": [ 1171 | { 1172 | "data": { 1173 | "text/plain": [ 1174 | "(1, 2, 3)" 1175 | ] 1176 | }, 1177 | "execution_count": 75, 1178 | "metadata": {}, 1179 | "output_type": "execute_result" 1180 | } 1181 | ], 1182 | "source": [ 1183 | "next(it), next(it), next(it)" 1184 | ] 1185 | }, 1186 | { 1187 | "cell_type": "code", 1188 | "execution_count": 76, 1189 | "id": "29fa6304-0e2a-4da0-a3c0-a50fc70980b2", 1190 | "metadata": {}, 1191 | "outputs": [ 1192 | { 1193 | "name": "stdout", 1194 | "output_type": "stream", 1195 | "text": [ 1196 | "1 2 3\n" 1197 | ] 1198 | } 1199 | ], 1200 | "source": [ 1201 | "lst = [1, 2, 3, 4, 5]\n", 1202 | "it = iter(lst)\n", 1203 | "\n", 1204 | "print(next(it), next(it), next(it))\n", 1205 | "\n", 1206 | "lst.insert(2, -1)\n", 1207 | "lst.insert(0, -1)" 1208 | ] 1209 | }, 1210 | { 1211 | "cell_type": "code", 1212 | "execution_count": 78, 1213 | "id": "382adceb-9c8a-4e25-a36b-fe340d56a54d", 1214 | "metadata": {}, 1215 | "outputs": [ 1216 | { 1217 | "data": { 1218 | "text/plain": [ 1219 | "-1" 1220 | ] 1221 | }, 1222 | "execution_count": 78, 1223 | "metadata": {}, 1224 | "output_type": "execute_result" 1225 | } 1226 | ], 1227 | "source": [ 1228 | "next(it)" 1229 | ] 1230 | }, 1231 | { 1232 | "cell_type": "code", 1233 | "execution_count": 81, 1234 | "id": "b1357991-1104-434c-a018-8176f7c5c201", 1235 | "metadata": {}, 1236 | "outputs": [], 1237 | "source": [ 1238 | "lst = [1, 2, 3, 4, 5]" 1239 | ] 1240 | }, 1241 | { 1242 | "cell_type": "code", 1243 | "execution_count": 82, 1244 | "id": "d6ef448e-66e5-438e-bffd-69bec7def4a5", 1245 | "metadata": {}, 1246 | "outputs": [ 1247 | { 1248 | "name": "stdout", 1249 | "output_type": "stream", 1250 | "text": [ 1251 | "1\n", 1252 | "3\n", 1253 | "5\n" 1254 | ] 1255 | } 1256 | ], 1257 | "source": [ 1258 | "for i in lst:\n", 1259 | " print(i)\n", 1260 | " lst.pop(0)" 1261 | ] 1262 | }, 1263 | { 1264 | "cell_type": "code", 1265 | "execution_count": null, 1266 | "id": "fd0b8f8d-17ff-42e8-9d60-51309f5a4ddd", 1267 | "metadata": {}, 1268 | "outputs": [], 1269 | "source": [] 1270 | }, 1271 | { 1272 | "cell_type": "code", 1273 | "execution_count": 91, 1274 | "id": "0dc4d226-556c-406d-942d-3e78d1daf84a", 1275 | "metadata": {}, 1276 | "outputs": [ 1277 | { 1278 | "data": { 1279 | "text/plain": [ 1280 | "(18122226, 4294967326)" 1281 | ] 1282 | }, 1283 | "execution_count": 91, 1284 | "metadata": {}, 1285 | "output_type": "execute_result" 1286 | } 1287 | ], 1288 | "source": [ 1289 | "len(range(-30, 2 ** 32, 237)), len(range(-30, 2 ** 32))" 1290 | ] 1291 | }, 1292 | { 1293 | "cell_type": "code", 1294 | "execution_count": null, 1295 | "id": "9b18283c-3c9b-4089-a759-d4d4192ea80c", 1296 | "metadata": {}, 1297 | "outputs": [], 1298 | "source": [] 1299 | }, 1300 | { 1301 | "cell_type": "code", 1302 | "execution_count": 84, 1303 | "id": "2c4e49f1-0f54-4d8d-8aa0-593cdcab47d7", 1304 | "metadata": {}, 1305 | "outputs": [ 1306 | { 1307 | "name": "stdout", 1308 | "output_type": "stream", 1309 | "text": [ 1310 | "start 10\n", 1311 | "yield 0\n", 1312 | "after yield 0\n", 1313 | "yield 1\n", 1314 | "after yield 1\n", 1315 | "yield 2\n", 1316 | "after yield 2\n", 1317 | "yield 3\n", 1318 | "after yield 3\n", 1319 | "yield 4\n", 1320 | "after yield 4\n", 1321 | "yield 5\n", 1322 | "after yield 5\n", 1323 | "yield 6\n", 1324 | "after yield 6\n", 1325 | "yield 7\n", 1326 | "after yield 7\n", 1327 | "yield 8\n", 1328 | "after yield 8\n", 1329 | "yield 9\n", 1330 | "after yield 9\n", 1331 | "[(0, 1), (2, 9), (4, 25), (6, 49), (8, 81)]\n" 1332 | ] 1333 | } 1334 | ], 1335 | "source": [ 1336 | "n = iter(range(10))\n", 1337 | "n = gen_step(10)\n", 1338 | "\n", 1339 | "result = list(\n", 1340 | " zip(\n", 1341 | " n,\n", 1342 | " map(lambda x: x ** 2, n)\n", 1343 | " )\n", 1344 | ")\n", 1345 | "print(result)" 1346 | ] 1347 | }, 1348 | { 1349 | "cell_type": "code", 1350 | "execution_count": 87, 1351 | "id": "a3442924-5b7e-40a8-b005-df8bb2c9e793", 1352 | "metadata": {}, 1353 | "outputs": [], 1354 | "source": [ 1355 | "n = gen_step(10)" 1356 | ] 1357 | }, 1358 | { 1359 | "cell_type": "code", 1360 | "execution_count": 88, 1361 | "id": "edc212ee-4a2b-4a2f-8d40-35c428eabb83", 1362 | "metadata": {}, 1363 | "outputs": [ 1364 | { 1365 | "ename": "TypeError", 1366 | "evalue": "object of type 'generator' has no len()", 1367 | "output_type": "error", 1368 | "traceback": [ 1369 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 1370 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 1371 | "Cell \u001b[0;32mIn[88], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mlen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mn\u001b[49m\u001b[43m)\u001b[49m\n", 1372 | "\u001b[0;31mTypeError\u001b[0m: object of type 'generator' has no len()" 1373 | ] 1374 | } 1375 | ], 1376 | "source": [ 1377 | "len(n)" 1378 | ] 1379 | }, 1380 | { 1381 | "cell_type": "code", 1382 | "execution_count": 89, 1383 | "id": "f18b5338-d3bd-4b83-a19d-15de8b11b9ba", 1384 | "metadata": {}, 1385 | "outputs": [ 1386 | { 1387 | "ename": "TypeError", 1388 | "evalue": "object of type 'SpecialIterator' has no len()", 1389 | "output_type": "error", 1390 | "traceback": [ 1391 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 1392 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 1393 | "Cell \u001b[0;32mIn[89], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;43mlen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mSpecialIterator\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m5\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n", 1394 | "\u001b[0;31mTypeError\u001b[0m: object of type 'SpecialIterator' has no len()" 1395 | ] 1396 | } 1397 | ], 1398 | "source": [ 1399 | "len(SpecialIterator(5))" 1400 | ] 1401 | }, 1402 | { 1403 | "cell_type": "code", 1404 | "execution_count": null, 1405 | "id": "b32fe9b5-3951-4fa8-8ac7-655fbf83cc9f", 1406 | "metadata": {}, 1407 | "outputs": [], 1408 | "source": [] 1409 | } 1410 | ], 1411 | "metadata": { 1412 | "kernelspec": { 1413 | "display_name": "Python 3 (ipykernel)", 1414 | "language": "python", 1415 | "name": "python3" 1416 | }, 1417 | "language_info": { 1418 | "codemirror_mode": { 1419 | "name": "ipython", 1420 | "version": 3 1421 | }, 1422 | "file_extension": ".py", 1423 | "mimetype": "text/x-python", 1424 | "name": "python", 1425 | "nbconvert_exporter": "python", 1426 | "pygments_lexer": "ipython3", 1427 | "version": "3.12.5" 1428 | } 1429 | }, 1430 | "nbformat": 4, 1431 | "nbformat_minor": 5 1432 | } 1433 | --------------------------------------------------------------------------------