{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Сегодня разбора домашней работы не будет, так как дедлайн продлили еще на один день" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "ename": "NameError", "evalue": "name 'do_something_with' is not defined", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0ms\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;34m\"first\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"second\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"third\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mdo_something_with\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0melem\u001b[0m \u001b[1;32min\u001b[0m \u001b[0ms\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mNameError\u001b[0m: name 'do_something_with' is not defined" ] } ], "source": [ "# Вот общее замечание для всех\n", "# Старайтесь итерироваться по элементам, а не по индексам!\n", "s = [\"first\", \"second\", \"third\"]\n", "for i in range(len(s)):\n", " do_something_with(s[i]) # Итерация по индексам - так можно, но зачем?\n", " \n", "for elem in s:\n", " do_something_with(elem) # Итерация по элементам - читать такой код приятнее!\n", "\n", "# Вопрос из зала про итерацию по матрице \n", "M = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\n", "\n", "for row in M:\n", " for elem in row:\n", " do_something_with(elem) # Нет проблем!\n", " \n", "# Конечно, если по смыслу вам нужны сами индексы - используйте их" ] }, { "cell_type": "code", "execution_count": 104, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Text in one line\n" ] } ], "source": [ "# Другое общее замечание - про ввод строк\n", "# Напоминаю: для чтения одной строки используйте старый добрый input()\n", "s = input()\n", "# Завершающего символа \\n в такой строке не будет" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Text in one line'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Если дальше по смыслу надо прочитать много строк (пока не кончатся), используйте sys.stdin:\n", "import sys\n", "\n", "for line in sys.stdin:\n", " do_something_with(line)\n", " line = line.rstrip(\"\\n\") # В конце каждой такой строки стоит \\n\n", " \n", "\n", "# Или вот так \n", "sys.stdin.read().rstrip(\"\\n\").split(\"\\n\")\n", "# (только обратите внимание, что rstrip уберет ВСЕ пустые строки в конце)\n", "\n", "# Или вообще вот так:\n", "lines = sys.stdin.readlines() # Символ \\n останется внутри каждой строки\n", "\n", "# Или так:\n", "lines = sys.stdin.read().splitlines() # Символы \\n в конце строк обрежутся\n", "\n", "# Вопрос из зала: как при вводе с клавиатуры завершить ввод?\n", "# Ответ: Ctrl+D - это и есть End of file\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Сегодня мы поговорим про пространства имен и классы" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "17\n" ] } ], "source": [ "# Это одинаковые или разные иксы? )\n", "\n", "x = 17\n", "\n", "def f():\n", " x = 42\n", " \n", " def g():\n", " x = \"abc\"\n", " \n", " \n", "f()\n", "\n", "print(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Каждое из этих имен x живет в своем \"пространстве имен\". Они разные\n", "\n", "# Вопрос из зала: а можно ли изменить аргумент, переданный как параметр в функцию?\n", "# Ответ: нет, по умолчанию присваивание вводит новое имя:\n", "\n", "x = 17\n", "def f(param):\n", " param = 42\n", "\n", "f(x)\n", "print(x)\n" ] }, { "cell_type": "code", "execution_count": 105, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4]\n" ] } ], "source": [ "# Впрочем, если бы это был изменяемый объект (список, словарь, множество и т. д.),\n", "# то он передался бы по ссылке, и его содержимое можно было бы менять:\n", "\n", "x = [1, 2, 3]\n", "\n", "def f(param):\n", " param.append(4)\n", " \n", "f(x)\n", "print(x)" ] }, { "cell_type": "code", "execution_count": 106, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3]\n" ] } ], "source": [ "# Но все равно вот так ничего бы не вышло:\n", "\n", "x = [1, 2, 3]\n", "\n", "def f(param):\n", " param = [1, 2, 3, 4] # Новое локальное имя, не имеющее отношение к аргументу\n", " \n", "f(x)\n", "print(x)" ] }, { "cell_type": "code", "execution_count": 107, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "42\n" ] } ], "source": [ "# По умолчанию чтение переменной ищет её имя в объемлющем пространстве имен, если оно не найдено в текущем\n", "# Ключевое слово global позволяет сказать, что присваивание должно брать имя из глобального пространства имен\n", "\n", "x = 17\n", "\n", "def f():\n", " global x\n", " x = 42\n", " \n", "f()\n", "print(x)" ] }, { "cell_type": "code", "execution_count": 109, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "g: 123\n", "f: 123\n", "global: 17\n" ] } ], "source": [ "# А ключевое слово nonlocal говорит, что имя надо взять из пространства имен на уровень выше:\n", "\n", "x = 17\n", "\n", "def f():\n", " x = 42\n", " \n", " def g():\n", " nonlocal x\n", " x = 123\n", " print(\"g:\", x)\n", " \n", " g()\n", " print(\"f:\", x)\n", " \n", "f()\n", "print(\"global:\", x)\n", "\n", "# Злоупотреблять этим не следует\n", "# Старайтесь писать программы, в которых не приходилось бы использовать global и nonlocal" ] }, { "cell_type": "code", "execution_count": 111, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "In class C\n" ] } ], "source": [ "# Класс в первом приближении выглядит просто как пространство имён:\n", "\n", "class C:\n", " # Тут могут быть любые операторы\n", " x = 42\n", " s = \"Hello\"\n", " print(\"In class C\")\n", " \n", " def f(a, b):\n", " print(a)\n", " print(b)\n", " \n", " \n" ] }, { "cell_type": "code", "execution_count": 112, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "42" ] }, "execution_count": 112, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.x # Обращаемся к атрибутам - класс ведет себя как пространство имён" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Hello'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.s" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.f" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n" ] } ], "source": [ "C.f(1, 2)" ] }, { "cell_type": "code", "execution_count": 113, "metadata": { "collapsed": true }, "outputs": [], "source": [ "C.y = 3.1415 # Можно смело вводить новые атрибуты" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3.1415" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.y" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": true }, "outputs": [], "source": [ "del C.x # И удалять их" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AttributeError", "evalue": "type object 'C' has no attribute 'x'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mC\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m: type object 'C' has no attribute 'x'" ] } ], "source": [ "C.x" ] }, { "cell_type": "code", "execution_count": 116, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Но классы - это еще и \"шаблоны\" для создания объектов\n", "\n", "import math\n", "class Point:\n", " \n", " color = \"black\"\n", " \n", " def __init__(self, x, y): # Предопределенное имя - функция, создающая объект\n", " # self - сам создаваемый по образцу объект\n", " self.x = x\n", " self.y = y\n", " \n", " def distance(self, other):\n", " return math.sqrt(\n", " (self.x - other.x)**2 + (self.y - other.y)**2\n", " )\n", " " ] }, { "cell_type": "code", "execution_count": 117, "metadata": { "collapsed": true }, "outputs": [], "source": [ "p = Point(1, 2)" ] }, { "cell_type": "code", "execution_count": 118, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.x" ] }, { "cell_type": "code", "execution_count": 119, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 119, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.y" ] }, { "cell_type": "code", "execution_count": 120, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'black'" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.color" ] }, { "cell_type": "code", "execution_count": 121, "metadata": { "collapsed": true }, "outputs": [], "source": [ "q = Point(3, -4)" ] }, { "cell_type": "code", "execution_count": 122, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 122, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q.x" ] }, { "cell_type": "code", "execution_count": 123, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "-4" ] }, "execution_count": 123, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q.y" ] }, { "cell_type": "code", "execution_count": 124, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'black'" ] }, "execution_count": 124, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q.color" ] }, { "cell_type": "code", "execution_count": 126, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "6.324555320336759" ] }, "execution_count": 126, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.distance(q) # вызываем метод distance у объекта p с параметром q" ] }, { "cell_type": "code", "execution_count": 127, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "6.324555320336759" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Фактически это сводится вот к такому вызову:\n", "Point.distance(p, q)" ] }, { "cell_type": "code", "execution_count": 128, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'abc'" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Помните, мы много раз использовали методы стандартных объектов - списков, строк?\n", "# Например:\n", "s = \"ABC\"\n", "s.lower()" ] }, { "cell_type": "code", "execution_count": 129, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'abc'" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# А можно было бы и так:\n", "str.lower(s)\n", "\n", "# Мы этим неявно пользуемся, когда передаем str.lower в качестве ключа для сортировки" ] }, { "cell_type": "code", "execution_count": 130, "metadata": { "collapsed": true }, "outputs": [], "source": [ "t = Point(5, 6)" ] }, { "cell_type": "code", "execution_count": 131, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'black'" ] }, "execution_count": 131, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.color" ] }, { "cell_type": "code", "execution_count": 132, "metadata": { "collapsed": true }, "outputs": [], "source": [ "t.color = \"green\" # Можно менять атрибуты у самих объектов" ] }, { "cell_type": "code", "execution_count": 136, "metadata": { "collapsed": true }, "outputs": [], "source": [ "Point.color = \"white\" # А можно поменять у самого класса." ] }, { "cell_type": "code", "execution_count": 138, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'white'" ] }, "execution_count": 138, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.color # У p не было своего атрибута color" ] }, { "cell_type": "code", "execution_count": 137, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'green'" ] }, "execution_count": 137, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.color # А у t он был" ] }, { "cell_type": "code", "execution_count": 140, "metadata": { "collapsed": true }, "outputs": [], "source": [ "del t.color # Теперь и у t его нет" ] }, { "cell_type": "code", "execution_count": 141, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'white'" ] }, "execution_count": 141, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t.color # Поэтому его имя ищется в объемлющем пространстве имен - в самом классе" ] }, { "cell_type": "code", "execution_count": 142, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Объекты класса вообще можно использовать прямо так\n", "\n", "class A:\n", " pass # пустой класс\n", "\n", "\n", "a = A()\n", "a.x = 1\n", "a.y = 2\n", "\n", "\n", "b = A()\n", "b.s = \"Hello\"\n", "b.z = \"Good bye\"" ] }, { "cell_type": "code", "execution_count": 100, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Рассмотрим теперь упрощенный пример класса \"Рациональное число\"\n", "\n", "# Вспомогательная функция для вычисления НОД по алгоритму Евклида\n", "def gcd(x, y):\n", " # НОД(x, y) = НОД(y, x % y)\n", " while y != 0:\n", " x, y = y, x % y\n", " return x\n", "\n", "\n", "class Rational: \n", " def __init__(self, x, y):\n", " d = gcd(x, y)\n", " self.numerator = x // d # Сократим на общий знаменатель\n", " self.denominator = y // d\n", " if self.denominator < 0: # Поправим знак числителя и знаменателя при необходимости\n", " self.numerator *= -1\n", " self.denominator *= -1\n", " \n", " def __str__(self): # Строковое предстваление нашего числа\n", " return str(self.numerator) + \" / \" + str(self.denominator)\n", " \n", " def __abs__(self): # Модуль числа\n", " return Rational(abs(self.numerator), abs(self.denominator))\n", " \n", " def __add__(self, other): # Сумма рациональных чисел\n", " return Rational(\n", " self.numerator * other.denominator +\n", " self.denominator * other.numerator,\n", " self.denominator * other.denominator\n", " )\n", " \n", " # При желании можно переопределить и другие операторы\n", " " ] }, { "cell_type": "code", "execution_count": 143, "metadata": { "collapsed": true }, "outputs": [], "source": [ "p = Rational(-3, 6)" ] }, { "cell_type": "code", "execution_count": 144, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 / 2\n" ] } ], "source": [ "print(abs(p))" ] }, { "cell_type": "code", "execution_count": 146, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "-1" ] }, "execution_count": 146, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.numerator" ] }, { "cell_type": "code", "execution_count": 147, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 147, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.denominator" ] }, { "cell_type": "code", "execution_count": 148, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-1 / 1\n" ] } ], "source": [ "print(p + p)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.4.3" } }, "nbformat": 4, "nbformat_minor": 0 }