аа. Документ Microsoft Word. Лабораторная работа ооп." , "cell type" "code", "execution count"
Скачать 44.82 Kb.
|
{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Лабораторная работа 4. ООП." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "import pylab\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Создание классов и объектов\n", "В языке программирования Python классы создаются с помощью инструкции class, за которой следует произвольное имя класса, после которого ставится двоеточие, далее с новой строки и с отступом реализуется тело класса:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "class A: # class ИмяКласса:\n", " pass # тело_класса" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Создание экземпляра класса:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "a = A() # имя_переменной = ИмяКласса()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "<__main__.A object at 0x00000178AB41DBE0> объект класса ] } ], "source": [ "print(a, 'объект класса', type(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1.1. Класс как модуль (библиотека)\n", "Класс можно представить подобно модулю (библиотеки), в нем могут быть свои переменные со значениями и функции, у класса есть собственное пространство имен, доступ к которым возможен через имя класса:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "class CLASS:\n", " const = 5 # атрибут класса\n", " def adder(v): # функция-метод\n", " return v + CLASS.const" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "CLASS.const" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "CLASS.adder(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1.2. Класс как создатель объектов\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "Object = CLASS()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Object.const" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "adder() takes 1 positional argument but 2 were given", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m "\u001b[1;31mTypeError\u001b[0m: adder() takes 1 positional argument but 2 were given" ] } ], "source": [ "Object.adder(100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Дело в том, что классы и объекты не просто модули. Класс создает объекты, которые в определенном смысле являются его наследниками (копиями). \n", "\n", "Это значит, что если у объекта нет собственного поля const, то интерпретатор ищет его уровнем выше, то есть в классе. Таким образом, если мы присваиваем объекту поле с таким же именем как в классе, то оно перекрывает, т. е. переопределяет, поле класса:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Object.const" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Object.const = 10\n", "Object.const" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "CLASS.const" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Видно что Object.const и CLASS.const – это разные переменные. \n", "\n", "Object.const находится в пространстве имен объекта Object. \n", "\n", "CLASS.const – в пространстве класса CLASS. \n", "\n", "Если не задовать поле const объекту Object, то интерпретатор бы поднялся выше по дереву наследования и пришел бы в класс, где бы и нашел это поле.\n", "\n", "Методы также наследуются объектами класса. В данном случае у объекта Object нет своего собственного метода adder, значит, он ищется в классе CLASS. Однако, от класса B может быть порождено множество объектов. И методы предназначаются для обработки объектов. Таким образом, когда вызывается метод, в него надо передать конкретный объект, который он будет обрабатывать.\n", "\n", "\n", "Выражение Object.adder(100) выполняется интерпретатором следующим образом:\n", "\n", "- Ищу атрибут adder() у объекта Object. Не нахожу.\n", "\n", "- Тогда иду искать в класс CLASS, так как он создал объект Object.\n", "\n", "- Здесь нахожу искомый метод. Передаю ему объект, к которому этот метод надо применить, и аргумент, указанный в скобках.\n", "\n", "Другими словами, выражение Object.adder(100) преобразуется в выражение CLASS.adder(Object, 100).\n", "\n", "Таким образом, интерпретатор попытался передать в метод adder() класса CLASS два параметра – объект Object и число 100. Но мы запрограммировали метод adder() так, что он принимает только один параметр. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Однако:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'CLASS' and 'int'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m "\u001b[1;32m "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'CLASS' and 'int'" ] } ], "source": [ "Object.adder()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Получается странная ситуация. Ведь adder() вызывается не только через класса, но и через порожденные от него объекты. Однако в последнем случае всегда будет возникать ошибка. \n", "\n", "Может понадобиться метод с параметрами, но которому не надо передавать экземпляр данного класса. Для таких ситуаций предназначены статические методы. Такие методы могут вызываться через объекты данного класса, но сам объект в качестве аргумента в них не передается.\n", "\n", "В Python острой необходимости в статических методах нет, так как код может находиться за пределами класса, и программа не начинает выполняться из класса. Если нам нужна просто какая-нибудь функция, мы можем определить ее в основной ветке. Однако в Python тоже можно реализовать подобное, то есть статические методы, с помощью декоратора @staticmethod:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "class CLASS:\n", " const = 5 # атрибут класса\n", " @staticmethod \n", " def adder(v): # функция-метод\n", " return v + CLASS.const" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "Object = CLASS()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Object.adder(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Статические методы в Python – по-сути обычные функции, помещенные в класс для удобства и находящиеся в пространстве имен этого класса. Это может быть какой-то вспомогательный код. \n", "\n", "Вообще, если в теле метода не используется self, то есть ссылка на конкретный объект, имеет смысл сделать метод статическим." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1.3. Изменение полей объекта\n", "\n", "В Python объекту можно не только переопределять поля и методы, унаследованные от класса, также можно добавить новые, которых нет в классе:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "Object1 = CLASS()\n", "Object2 = CLASS()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'abcd'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Object2.str = 'abcd'\n", "Object2.str" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'CLASS' object has no attribute 'str'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m "\u001b[1;31mAttributeError\u001b[0m: 'CLASS' object has no attribute 'str'" ] } ], "source": [ "Object1.str" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "type object 'CLASS' has no attribute 'str'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m "\u001b[1;31mAttributeError\u001b[0m: type object 'CLASS' has no attribute 'str'" ] } ], "source": [ "CLASS.str" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Однако в программировании так делать не принято, потому что тогда объекты одного класса будут отличаться между собой по набору атрибутов. Это затруднит автоматизацию их обработки, внесет в программу хаос.\n", "\n", "Поэтому принято присваивать полям, а также получать их значения, путем вызова методов (сеттеров (set – установить) и геттеров (get – получить)):" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "class CLASS:\n", " def setName(self, n):\n", " self.name = n \n", " def getName(self):\n", " try:\n", " return self.name\n", " except:\n", " return \"No name\"" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "first = CLASS()\n", "second = CLASS()" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Bob'" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "first.setName(\"Bob\")\n", "first.getName()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No name\n" ] } ], "source": [ "print(second.getName())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1.4. Специальные методы\n", "\n", "# Конструктор класса (метод $__init__()$)\n", "\n", "В объектно-ориентированном программировании конструктором класса называют метод, который автоматически вызывается при создании объектов. Его также можно назвать конструктором объектов класса. Имя такого метода обычно регламентируется синтаксисом конкретного языка программирования. \n", "\n", "В Python роль конструктора играет метод $__init__()$.\n", "\n", "В Python наличие пар знаков подчеркивания спереди и сзади в имени метода говорит о том, что он принадлежит к группе методов перегрузки операторов. Если подобные методы определены в классе, то объекты могут участвовать в таких операциях как сложение, вычитание, вызываться как функции и др.\n", "\n", "При этом методы перегрузки операторов не надо вызывать по имени. Вызовом для них является сам факт участия объекта в определенной операции. В случае конструктора класса – это операция создания объекта. Так как объект создается в момент вызова класса по имени, то в этот момент вызывается метод $__init__()$, если он определен в классе.\n", "\n", "Необходимость конструкторов связана с тем, что нередко объекты должны иметь собственные свойства сразу. \n", "\n", "Пусть имеется класс Person, объекты которого обязательно должны иметь имя и фамилию:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "class Person:\n", " def setName(self, n, s):\n", " self.name = n\n", " self.surname = s" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "p1 = Person()\n", "p1.setName(\"Bill\", \"Ross\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ИЛИ" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": 'true' }, "outputs": [], "source": [ "class Person:\n", " def __init__(self, n, s):\n", " self.name = n\n", " self.surname = s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В свою очередь, конструктор класса не позволит создать объект без обязательных полей:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "__init__() missing 2 required positional arguments: 'n' and 's'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m |