{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Парадигмы программирования\n", "\n", "В отличии от Fortran или С которые поддерживают только парадигму процедурного программирования Python позволяет писать код также в объектно-ориентированном и функциональном стилях.\n", "\n", "## Объектно-ориентированное программировние (ООП)\n", "ООП основанное на использовании специальных типов - классов, которые объеденяют данные и способы работы с ними. \n", "\n", "В языке Pascal вы можете создать переменную типа string и например передать её в функцию ToUpperCase:\n", " ```pascal\n", " variable := 'AaBb'\n", " toUpperCase(variable)\n", " // Теперь variable содержит строку 'AABB'\n", " ```\n", " Но приведение к верхнему регистру это операция характерная для строк, бессмысленно пытаться приводить целое число к нему. Поэтому ООП предлагает превратить функцию ToUpperCase в _метод_ класса, иначе говоря в функцию-член класса.\n", "Рассмотрим пример:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"AaBb\"\n", "type(a)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В переменную `a` мы сохранили строку \"AaBb\", которая явлется экземпляром (объектом) класса `str`. Теперь мы можем вызвать у переменной `a` один из методов класса `str`." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'AABB'" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.upper()" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Метод может принимать аргументы (на самом деле любой метод принимает как минимум один аргумент подробнее [здесь]())\n", "# Например посчитаем сколько раз буква A входит в строку\n", "a.count('A')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'My name is Mikahil, my age is 24 and my temperature is 36.6 degree.'" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Возвращаясь к форматированию строк, \n", "# то наилучшим способом будет использования метода format\n", "\"My name is {}, my age is {:d} and my temperature is {:.1f} degree.\".format(\"Mikahil\", 24, 36.6)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1, 2)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = 0.5 # Числа тоже имеют методы\n", "a.as_integer_ratio() # Представляет вещественное число как отношение целых" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['__abs__',\n", " '__add__',\n", " '__bool__',\n", " '__class__',\n", " '__delattr__',\n", " '__dir__',\n", " '__divmod__',\n", " '__doc__',\n", " '__eq__',\n", " '__float__',\n", " '__floordiv__',\n", " '__format__',\n", " '__ge__',\n", " '__getattribute__',\n", " '__getformat__',\n", " '__getnewargs__',\n", " '__gt__',\n", " '__hash__',\n", " '__init__',\n", " '__init_subclass__',\n", " '__int__',\n", " '__le__',\n", " '__lt__',\n", " '__mod__',\n", " '__mul__',\n", " '__ne__',\n", " '__neg__',\n", " '__new__',\n", " '__pos__',\n", " '__pow__',\n", " '__radd__',\n", " '__rdivmod__',\n", " '__reduce__',\n", " '__reduce_ex__',\n", " '__repr__',\n", " '__rfloordiv__',\n", " '__rmod__',\n", " '__rmul__',\n", " '__round__',\n", " '__rpow__',\n", " '__rsub__',\n", " '__rtruediv__',\n", " '__setattr__',\n", " '__setformat__',\n", " '__sizeof__',\n", " '__str__',\n", " '__sub__',\n", " '__subclasshook__',\n", " '__truediv__',\n", " '__trunc__',\n", " 'as_integer_ratio',\n", " 'conjugate',\n", " 'fromhex',\n", " 'hex',\n", " 'imag',\n", " 'is_integer',\n", " 'real']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dir(a) # Позволяет узнать методы, определенные у объекта,\n", " # методы начинающиеся с двойного подчеркивая --- служебные и обычно явно не вызываются" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### In-place и Out-of-place операции\n", "Операции проводимые _in place_ производятся непосредвенно с объектом вызвашим эту операцию, а _out of place_ создают новый объект. Сравним два примера." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Список data изменился: [1, 2, 3]\n" ] } ], "source": [ "data = [1, 3, 2]\n", "data.sort()\n", "print(\"Список data изменился: {}\".format(data))" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Список data не изменился: [1, 3, 2]\n", "Список res содержит результат сортировки: [1, 2, 3]\n" ] } ], "source": [ "data = [ 1,3,2]\n", "res = sorted(data)\n", "print(\"Список data не изменился: {}\".format(data))\n", "print(\"Список res содержит результат сортировки: {}\".format(res))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В первом примере вызов метода sort отсортировал список data, во втором примере функция sorted создала новый отсртированный список оставив порядок элементов в data неизменным " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Пользовательские типы (Дополнительный материал)\n", "Однако мы можем использовать не только классы изначально сушествующие в языке, но и создавать свои!" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "class VelocityVector2D:\n", " \"\"\"\n", " Класс описывающий двумерный вектор скорости\n", " \"\"\"\n", " units = \"м/c\"\n", " \n", " def __init__(self, x, y):\n", " \"\"\"\n", " Значение переменных x,y считается данным в м\\с\n", " \"\"\"\n", " self.x = x\n", " self.y = y\n", " \n", " def module(self, system_of_units = \"SI\"):\n", " \"\"\"\n", " Модуль вектора скорости\n", " Аргумент system_of_units может принимать значения \"SI\" и \"SGS\"\n", " \"\"\"\n", " module = (self.x**2 + self.y**2)**0.5\n", " if system_of_units==\"SI\":\n", " return module\n", " elif system_of_units==\"SGS\":\n", " return module*10 # Перевели из СИ в СГС\n", " else:\n", " raise Exception('Незнакомая система единиц')\n", " \n", " def __add__(self, another_vector):\n", " \"\"\"\n", " Позволяет складывать два вектора с помощью оператора +\n", " \"\"\"\n", " return VelocityVector2D(self.x + another_vector.x, self.y + another_vector.y)\n", " \n", " def __repr__(self):\n", " \"\"\"\n", " Генериует строковой представление для нашего класса\n", " Например, мы теперь можем сделать:\n", " print(VelocityVector2D(3,4))\n", " \"\"\"\n", " return \"Vx = {0} {2}, Vy = {1} {2}\".format(self.x, self.y , self.units)\n", " \n", " " ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "v1 = VelocityVector2D(3,4)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1.x" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.0" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1.module()" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Модуль скорости равен 5.0\n" ] } ], "source": [ "print(\"Модуль скорости равен {}\".format(v1.module()))" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vx = 0 м/c, Vy = 0 м/c" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v_rel = v1 + VelocityVector2D(-3,-4)\n", "print(v_rel)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Функциональное программирование (ФП)\n", "Одной из основ ФП является передача функции _в качестве аргумента для другой функции_. Для пример реализуем функцию которая будет вычислять интеграл от произвольной функции." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "def riman_integral(function, left_boundary = 0, rigth_boundary = 1, number_points = 200):\n", " \"\"\"\n", " Вычисляем интеграл методом прямоугольников.\n", " Это определенно не самый лучший способ численного интегрирования,\n", " но самый простой и для функций без особенностей дает приемлимую точность.\n", " Отметим что реализация данной функции основанно на чистом Python\n", " и поэтому не является оптимальной по производительности.\n", " О высокопроизводительных вычислениях смотри раздел Numpy и Scipy\n", " \"\"\"\n", " a, b = left_boundary, rigth_boundary \n", " dx = (b - a) / (number_points - 1) # Интервалов на один меньше чем точек\n", " res = function(a)\n", " for i in range(1, number_points - 1):\n", " res += function(a + i*dx)\n", " res += function(b)\n", " return res*dx\n", " " ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "from math import cos, pi" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.003941532222525" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# В качестве аргумента мы передаем функцию cos от которой вычисляем интеграл\n", "riman_integral(cos, 0, pi/2) # Вопрос на засыпку, верен ли результат?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Анонимные функции (дополнительный материал)\n", "\n", "Другим пример функционального стиля, является использование _аномнимных функций_. _Анонимные функции_ могут содержать лишь одно выражение. Создаются с помощью инструкции `lambda`. Рассмотрим на примере такой задачи: дан набор скоростей, нужно получить набор отсортированный по модулю скорости." ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Текущий порядок\n", "Vx = 0 м/c, Vy = 0 м/c\n", "Vx = 1 м/c, Vy = 1 м/c\n", "Vx = 0.1 м/c, Vy = 0.5 м/c\n" ] } ], "source": [ "data = [VelocityVector2D(0,0),\n", " VelocityVector2D(1,1),\n", " VelocityVector2D(0.1,0.5)]\n", "print(\"Текущий порядок\")\n", "for element in data:\n", " print(element)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Порядок после сортировки\n", "Vx = 0 м/c, Vy = 0 м/c\n", "Vx = 0.1 м/c, Vy = 0.5 м/c\n", "Vx = 1 м/c, Vy = 1 м/c\n" ] } ], "source": [ "result = sorted(data, # Входные данные\n", " key = lambda velocity : velocity.module() # Функция принимающая в качестве аргумента элемент из data\n", " # и определяющая порядок сортировки\n", " )\n", "print(\"Порядок после сортировки\")\n", "for element in result:\n", " print(element)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] } ], "source": [ "# Анонимная функция так же может иметь несколько аргументов\n", "print((lambda x, y: x * y)(1, 2))" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [default]", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.7" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": false, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": false, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }