На этом шаге мы поговорим о необходимости использования классов и объектов.
А что нам дает создание объектов на основе класса? К чему все эти хлопоты? Не лучше ли было просто вывести фразу "Гав!" без какого-либо дополнительного кода?
Прежде всего, это имеет смысл делать тогда, когда возникает необходимость в создании множества однотипных объектов. Создавая эти объекты по единому образцу на основе класса, а не описывая полностью каждый из них по отдельности, вы экономите массу времени. Но реальное преимущество объектов заключается в том, что они обеспечивают компактное объединение данных и функциональности в одном месте. Централизованная организация фрагментов кода в виде объектов, которым они естественным образом принадлежат, значительно облегчает понимание структуры программы, особенно в случае сложных задач, что является большим плюсом для программистов. Собаки лают. Кнопки реагируют на щелчки. Динамики издают звуки. Принтеры печатают или жалуются, если закончилась бумага. Во многих компьютерных системах кнопки, динамики и принтеры действительно являются объектами, функции которых вы активизируете.
Функции, принадлежащие объектам, называют методами. С включением функций в состав объектов вы уже сталкивались, когда мы добавляли функцию bark() в определение класса Dog, и созданные на основе этого класса объекты sizzles и mutley включали в себя данный метод. Вы видели, что оба они "лаяли" в рассмотренном примере!
Нейронные сети принимают некоторые входные данные (входной сигнал), выполняют некоторые вычисления и выдают выходные данные (выходной сигнал). Вы также знаете, что их можно тренировать. Вы уже видели, что эти действия - тренировка и выдача ответа - являются естественными функциями нейронной сети, т.е. их можно рассматривать в качестве функций объекта нейронной сети. Вы также помните, что с нейронными сетями естественным образом связаны относящиеся к ним внутренние данные - весовые коэффициенты связей между узлами. Вот почему мы будем создавать нашу нейронную сеть в виде объекта.
Чтобы вы получили более полное представление о возможностях объектов, давайте добавим в класс переменные, предназначенные для хранения специфических данных конкретных объектов, а также методы, позволяющие просматривать и изменять эти данные.
Взгляните на приведенное ниже обновленное определение класса Dog. Оно включает ряд новых элементов, которые мы рассмотрим по отдельности. # определение класса объектов Dog
class Dog: # метод для инициализации объекта внутренними данными def __init__(self, petname, temp): self.name = petname; self.temperature = temp; # получить состояние def status(self): print("имя собаки: ", self.name) print("температура собаки: ", self.temperature) # задать температуру def setTemperature(self, temp): self.temperature = temp; # собаки могут лаять def bark(self): print("Гав!")
Прежде всего, обратите внимание на то, что мы добавили в класс Dog три новые функции. У нас уже была функция bark(), а теперь мы дополнительно включили в класс функции __init__(), status() и setTemperature(). Процедура добавления новых функций достаточно очевидна. Чтобы собака могла не только лаять с помощью функции bark(), мы при желании могли бы дополнительно предоставить ей возможность чихать с помощью функции sneeze().
Но что это за переменные, указанные в круглых скобках после имен новых функций? Например, функция setTemperature фактически определена как setTemperature(self, temp). Функция со странным названием __init__() фактически определена как __init__(self, petname, temp). Эти переменные, получения значений которых функции ожидают во время вызова, называются параметрами. Помните функцию вычисления среднего avg(х, у), с которой вы уже сталкивались? Определение функции avg() явно указывало на то, что функция ожидает получения двух параметров. Следовательно, функция __init__() нуждается в параметрах petname и temp, а функция setTemperature() - только в параметре temp.
Заглянем внутрь этих функций. Начнем с функции с необычным названием __init__(). Зачем ей присвоено такое замысловатое имя?
Это специальное имя, и Python будет вызывать функцию __init__() каждый раз при создании нового объекта данного класса. Это очень удобно для выполнения любой подготовительной работы до фактического использования объекта. Так что же именно происходит в этой магической функции инициализации? Мы создаем две новые переменные: self.name и self.temperature. Вы можете узнать их значения из переменных petname и temp, передаваемых функции. Часть self, в именах означает, что эти переменные являются собственностью объекта, т.е. принадлежат данному конкретному объекту и не зависят от других объектов Dog или общих переменных Python. Мы не хотим смешивать имя данной собаки с именем другой! Если это кажется вам слишком сложным, не беспокойтесь, все значительно упростится, когда мы приступим к рассмотрению конкретного примера.
Следующая на очереди - функция status(), которая действительно проста. Она не принимает никаких параметров и просто выводит значения переменных name и temperature объекта Dog.
Наконец, функция setTemperature() принимает параметр temp, значение которого при ее вызове присваивается внутренней переменной self.temperature. Это означает, что даже после того, как объект создан, вы можете в любой момент изменить его температуру, причем это можно сделать столько раз, сколько потребуется. Мы не будем тратить время на обсуждение того, почему все эти функции, включая bark(), принимают атрибут self в качестве первого параметра. Это особенность Python, и таков ход его эволюции. По замыслу разработчиков это должно напоминать Python, что функция, которую вы собираетесь определить, принадлежит объекту, ссылкой на который служит self.
Чтобы прояснить все, о чем мы говорили, рассмотрим конкретный пример. В приведенном ниже коде вы видите обновленный класс Dog, определенный с новыми функциями, и новый объект lassie, создаваемый с параметрами, один из которых задает его имя как "Lassie", а другой устанавливает его температуру равной 37.
# создать новый объект собаки на основе класса Dog lassie = Dog("Lassie", 37) lassie.status() имя собаки: Lassie температура собаки: 37
Рис.1. Создание объекта обновленного класса Dog
Как видите, вызов функции status() для объекта lassie класса Dog обеспечивает вывод его имени и текущего значения температуры. С момента создания объекта эта температура не изменялась.
Попытаемся изменить температуру объекта и проверим, действительно ли она изменилась, введя следующий код.
lassie.SetTemperature(40)
lassie.status()
Результат представлен ниже.
Рис.2. Изменение значения температуры
Как видите, вызов функции setTemperature(40) действительно изменил внутреннее значение температуры объекта.
Мы должны быть довольны собой, поскольку узнали довольно много об объектах, которые многие считают сложной темой, но для нас она оказалась не таким уж трудным орешком!
Сейчас нам известно достаточно много о Python, чтобы мы могли самостоятельно создать собственную нейронную сеть.
На следующем шаге мы займемся разработкой проекта нейронной сети.