Как называется метод класса который вызывается при создании объектов этого класса
Перейти к содержимому

Как называется метод класса который вызывается при создании объектов этого класса

  • автор:

Информатика. 11 класс (Повышенный уровень)

Для начальной инициализации класса используются конструкторы. Конструктор — специальный тип метода класса, который автоматически вызывается при создании объекта этого же класса. Конструкторы обычно используются для инициализации полей объекта класса (пример 2.3).

В отличие от обычных методов конструкторы имеют определенные правила именования:

  • конструктор должен иметь то же имя, что и класс;
  • конструктор не имеет типа возврата.

В классе может быть несколько конструкторов. Конструктор, который не имеет параметров, называется конструктором по умолчанию. Он вызывается, если пользователем не указаны значения для инициализации. Конструкторы также могут быть объявлены с параметрами, которые используются для инициализации полей. В классе можно определить любое количество конструкторов, каждый из которых должен иметь уникальные параметры.

В конструкторе может быть использован список инициализации полей класса. Список инициализации располагается после параметров конструктора. Он начинается с двоеточия (:), а затем значение для каждого поля указывается в круглых скобках. В теле конструктора не нужно выполнять операции присваивания, поэтому тело конструктора может быть пустым. Список инициализации членов класса не заканчивается точкой с запятой (пример 2.4).

Каждый метод класса неявно содержит в качестве поля данных указатель:

ИмяКласса * this ;

С его помощью метод класса определяет, с данными какого объекта ему предстоит работать. Указатель this можно использовать в конструкторах (пример 2.5).

Деструктор класса — еще один специальный метод — вызывается при уничтожении объекта. Имя деструктора аналогично имени конструктора, только в начале ставится знак тильды: ~. Деструктор не имеет входных параметров. Деструктор всегда один. Для простых классов (тех, которые только инициализируют значения обычных свойств) деструктор не нужен, так как C++ автоматически выполнит очистку памяти самостоятельно. Деструкторы не вызываются пользователем явно. Однако их могут безопасно вызывать другие методы класса, т. к. объект не уничтожится до тех пор, пока не выполнится деструктор.

Пример 2.3. Добавление конструкторов в класс Student.

class Student

/** поля для хранения фамилии

и названия города **/

string fam , gorod ;

/// поле — год рождения

vector < int > otm = vector < int >( 3 );

/// конструктор по умолчанию

Student ( string f , string g , int r ,

int n0 , int n1 , int n2 );

/// метод для вычисления суммы отметок

/// сеттеры для задания значения полей

void set _ fam ( string f );

void set_gorod ( string g );

void set_god_r ( int r );

void set_otm ( vector < int > d );

/** геттер для получения строки

Фамилия Город Сумма баллов**/

Student::Student ( string f , string g ,

int r , int n0 , int n1 , int n2 )

Функция для ввода данных с использованием конструктора изменится следующим образом:

void vvod1 ( vector < Student >& d )

ifstream fin ( «input.txt» );

d . resize ( r );

/** Считывание данных из файла и

определение объектов с

for ( int i = 0 ; i < r ; i ++)

string t_str , g_str ;

int b0 , b1 , b2 ;

fin >> b0 >> b1 >> b2 ;

d [ i ] = Student ( t_str , g_str ,

t_int , b0 , b1 , b2 );

Пример 2.4. Использование списка инициализации при описании конструкторов в классе Student.

/// конструктор по умолчанию

Student () : gorod ( «Минск» ), god _ r ( 2005 ) <>

Student ( string f , string g , int r ,

int n0 , int n1 , int n2 ) :

fam ( f ), gorod ( g ),

Переменные в списке иниц иализации получают свои значения не в том порядке, в котором они указаны, а в том порядке, в котором объявлены в классе. Поэтому при использовании списков инициализации лучше сохранять тот же порядок полей, который задан при описании класса.

Пример 2.5. Использование указателя this в конструкторе класса Date.

Date :: Date ( int t_d , int t_m , int t_g )

this -> d = t_d ;

this -> m = t_m ;

this -> g = t_g ;

Как называется метод класса который вызывается при создании объектов этого класса

или объектное , программирование (в дальнейшем ООП ) – парадигма программирования, в которой основными концепциями являются понятия объектов и классов .

Класс — разновидность абстрактного типа данных, то есть такой тип данных, который содержит в себе элементы данных других типов. Класс может включать в себя функции и данные, при этом всё содержащееся в классе именуется членами класса . Данные класса именуются данными-членами или полями , а функции – или методами .

Объект – экземпляр класса. Таким образом, класс – это только тип данных, описываемый программистом, а объект – это уже экземпляр этого класса. То есть, яблоко – это класс, а висящее на конкретной яблоне в конкретном саду яблоко – уже объект.

В языке C++ классы описываются ключевым словом class :

Приведём в качестве примера описание класса Apple , описывающего яблоко:

В данном примере мы имеем объявление собственного типа данных – класса Apple , а также создание объекта GreenApple класса Apple . Класс имеет поле color типа unsigned int , указывающий, какого цвета яблоко, а также метод eat() типа void . Сейчас Apple представляет собой класс, описывающий одну характеристику цвета и функцию «съесть».

При создании объекта вызывается конструктор класса . Конструктор класс – это метод класса, вызываемый при создании объекта и служащий для задания данным объекта начальных значений. Конструктор имеет то же имя, что и класс и не имеет типа. Указывать конструктор не обязательно; если конструктор не объявлен, при создании объекта будет вызван стандартный конструктор , который просто создаст объекта в памяти, при этом в них будет находиться «мусор», поэтому желательно всегда явно указывать конструктор, задающий начальные значения полям объекта.

В конструкторе для краткости может применяться список инициализации , который указывается через двоеточие сразу после списка параметров конструктора. В нём происходит инициализация параметров следующим образом:

Видно использование нового ключевого слова public , о нём речь пойдёт позже, пока же просто пишите «public:» перед объявлением всех членов класса, чтобы программа могла компилироваться.

Конструкторов может быть несколько, однако каждый должен иметь уникальный список параметров, по которому компилятор сможет отличить один конструктор от другого. В конструктор можно не передавать никаких параметров, можно передавать параметры, характеризующие поля объекта, а можно передать указатель на существующий объект, чтобы новый создавался по подобию уже созданного. В случае если аргумент конструктора – другой объект, говорят о конструкторе копирования .

Аргумент обязательно должен передаваться по ссылке, иначе при вызове конструктора копирования для передачи аргумента будет создаваться копия объекта при помощи того же конструктора копирования, таким образом, произойдёт рекурсивный вызов функции без возможности выхода из неё.

Ниже приведён пример обновлённого класса Apple , который включает новый параметр weight – вес яблока в граммах и объявления конструкторов вышеописанных трёх типов:

Первый – пустой конструктор, вызывающийся всегда, когда явно не указан вызов другого конструктора. В нём при помощи списка инициализации цвет яблока задаётся как белый, а вес – 100 грамм.

Далее идёт конструктор, в который передаются все параметры нового яблока (вес и цвет).

Последний конструктор – конструктор копирования, он копирует данные из другого объекта.

Обращения к членам класса осуществляется через «.» – оператор выбора члена , а если используется указатель на объект, то посредством – оператора непрямого выбора члена , который используется вместо точки.

Тело можно описать и вне описания самого класса, для этого используется следующая форма:

Оператор «::» называется оператором расширения видимости , он указывает, из какого класса данный метод, после оператора идёт собственно имя метода. В целом реализация метода вне класса не отличается от реализации обычной функции, только вместе с именем метода необходимо указывать класс, из которого этот метод, при помощи «::».

Сам метод обязан быть объявлен внутри класса, как на картинке выше, это называется прототипом функции – объявление функции с указанием типа возвращаемого значения, имени и списка параметров, без тела функции. Вместо тела функции используется точка с запятой. Имена переменных в списке параметров можно не указывать. Функция должна быть реализована также как и обычная функция в любом подходящем для этого месте программы после прототипа, с тем лишь отличием, что её можно использовать сразу после объявления прототипа. Далее идёт объявление прототипа функции func и её реализация, использование функции возможно сразу после строчки с прототипом, имя параметра при объявлении прототипа не указано:

Давайте добавим члены класса и дополним класс Apple до более полного описания яблока:

Здесь описаны новые методы ccal и price , возвращающие калорийность и цену яблока соответственно. Также созданы объекты GreenApple , RedApple и RedApple2 , демонстрирующие работу конструкторов. Для GreenApple вызван конструктор без параметров, для RedApple поля проинициализированы значениями белого цвета и веса в 500 грамм, а RedApple2 создан как копия RedApple и после создания имеет те жеполя, что и RedApple . Далее членам GreenApple присваиваются другие значения, зелёный цвет и вес, равный весу

Объектно-ориентированное программирование включает, помимо классов и объектов, ещё и такие понятия, как: наследование , инкапсуляция и полиморфизм .

Инкапсуляция – свойство классов предоставлять программисту только те методы для изменения полей системы, которые предусмотрены для данного класса. Решение задачи может потребовать сокрытие от программиста непосредственного доступа к полям класса. Например, в классе Apple может потребоваться скрыть от программиста возможность непосредственного доступа к весу яблока, чтобы программист не применял к нему операцию, например, синуса. Чтобы предотвратить непредназначенные для класса операции с полями, с полями следует использовать модификатор private :

В новом классе Apple не будет доступа к членам color и weight извне класса, ими смогут пользоваться только методы класса. Но как же тогда узнать вес яблока в программе? Всё просто, для этого лишь нужно объявить метод, возвращающий значение веса яблока, который можно использовать вне класса:

Здесь описана функция getWeight() , возвращающая вес яблока, таким образом, вес яблока теперь нельзя непосредственно изменить. Чтобы изменить вес яблока, можно описать void setWeight() , устанавливающую вес яблока, или, если требуется другой способ изменить вес, можно, например, описать метод void grow() , который «заставляет» яблоко расти, то есть увеличивать вес, изменять цвет и т.д.

Всего в C++ существует 3 вида членов класса, с точки зрения инкапсуляции: public , protected и private . public позволяет использовать член класса в любом мете программы, private – только изнутри класса, а protected используется вкупе с наследованием, о нём речь пойдёт ниже.

Стоит отметить, что методы тоже могут быть объявлены как private , однако, это используется реже, чем

члены класса по умолчанию private , поэтому, стоит явно указывать тип доступности членов класса, если он не private , желательно даже всегда это делать, чтобы не возникало двойственности.

Надо помнить, что конструктор класса обязательно должен быть иначе он не будет доступен извне класса, и его нельзя будет использовать.

Наследование – инструмент ООП, позволяющий создать новый класс на основе уже существующего. Ранее мы уже создавали объект на основе(по подобию) другого, уже существующего, когда реализовывали конструктор копирования. Надо понимать, что объект и класс – это не одно и то жеи то, что мы делали выше это лишь создание двух объектов одного класса, один из которых создан на основе другого, при этом их суть и поля остались одинаковы. Наследование жепозволяет создавать объекты с разными полями на основе уже существующих, но более детально описанных.

Наследование позволяет классифицировать классы, как, например, классифицируют животных и растения. Яблоко и груша – это фрукты, они имеют много общего, например, у них можно вычислить калорийность. В программе было быэкономичнее написать одну общую функцию int ccal() , возвращающую калорийность фрукта, без привязки к конкретному фрукту. Также оба фрукта имеют вес и цвет, что тоже можно описать один раз, экономя время на написание кода. В приведённом примере про фрукты класс фрукта будет именоваться базовым классом , причём он будет даже прямым базовым классом . Логично, что классы могут наследоваться не напрямую, класс фрукт может быть унаследован у класса растение, тогда класс растение будет базовым классом для классов яблоко и груша, однако он будет уже непрямым базовым классом . Базовый класс – это класс, от которого наследуется данный класс, если наследование напрямую – это прямой базовый класс , если через другие классы – непрямой базовый класс .

Говорят, что классы яблоко и груша унаследованы от классов растение и фрукт, или же, они – потомки классов растение и фрукт.
При наследовании члены базового класса частично или полностью переходят в потомок этого класса.

Наследование в C++ реализуется следующим образом:

Здесь Plant , Fruit , Apple и Pear – классы растение, фрукт, яблоко и груша соответственно. Механизм наследования реализуется таким образом, что объявляется сначала базовый класс, затем наследуемый, как обычный класс, только сразу после имени класса через двоеточие указывается имя базового класса.

Теперь можно говорить о том, что яблоко и груша – это фрукты и использовать методы для работы с фруктами.

При наследовании члены базового класса, указанные как public становятся и членами унаследованного класса тоже. не наследуются и остаются в базовом классе, таким образом, они не будут доступны в унаследованных. Модификатор protected позволяет решить проблему совместимости инкапсуляции и наследования, таким образом, члены класса, помеченные как protected , не будут доступны извне класса, как и private , однако наследуются и становятся доступны в унаследованных классах, как и public .

Наследование в C++ тоже бывает трёх видов: public , protected и private . Вид наследования указывается перед именем базового класса при описании потомка:

Здесь Fruit наследуется посредством public -наследования, а Apple и Pear посредством

При public-наследовании члены, указанные как protected и public в потомке остаются protected и public соответственно; при protected-наследовании protected и public члены базового класса станут protected ; при public и protected члены базового класса станут в потомке private .

Как и с инкапсуляцией, по умолчанию используется

Далее приведён пример, поясняющий вышесказанное:

Ниже мы видим пример использования общего члена для классов Apple и Pear :

Вызываемый метод ccal() – общий для классов Apple и Pear , так как они унаследованы от одного базового класса Fruit , содержащего этот метод. Однако, получается довольно плохой код, ведь яблоко и груша здесь, по сути, одно и тоже – это просто разные классы с разными названиями, неужели наследование столь бесполезно? Ведь было бы неплохо иметь функцию, которая вычисляет реальную калорийность груши и яблока, исходя из их особенностей, а также функцию роста, которая бы тоже работала в зависимости от особенностей конкретного фрукта.

На самом деле, есть средство ООП, позволяющее осуществить вышесказанное, это третий кит, на котором стоит ООП – полиморфизм .

Полиморфизм — это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта. Иными словами, мы можем воспользоваться функциями grow() и ccal() для экземпляров классов Apple и Pear и получить результат, исходя из особенностей этих классов. При этом, вдаваться в тип конкретного фрукта не необходимости, нам достаточно знать, что это фрукт, тогда мы можем воспользоваться этими функциями.

Пусть яблоко более калорийно, чем груша, зато груша быстрее растёт. Тогда пусть это будут следующие функции:

Но снова, вызвав функции ccal() и grow() для груши и яблока, мы получим, что они работают также как и в классах Fruit и Plant . Всё правильно, ведь классы Fruit и Plant не предполагают того, чтобы эти функции были изменены в потомках классов.

Для того, чтобы эти функции могли быть переопределены в потомках, стоит указать их как virtual :

Такие функции называют виртуальными – функции, которые могут быть переопределены в потомках данного класса и иметь другое тело, но иметь одно и то же имя.

Теперь, наконец, механизм наследования покажет нам свою мощь, и мы сможем пользоваться им также как и в реальной жизни – будем пользоваться общими функциями для классов, исходя из особенностей каждого класса. Например, все съедобные фрукты мы можем есть, тем не менее, для разных фруктов мы делаем это банан надо чистить, яблоки мыть и т.д. Переводя на язык C++ можно сказать, что фрукт – базовый класс для унаследованных от него классов банан и яблоко, он содержит виртуальную функцию eat() , и она переопределена в классах яблоко и банан, для банана появляется необходимость очистить хожуру, для яблока – помыть.

Если виртуальная функция в потомке базового класса не была переопределена, то будет вызвана функция базового класса.

Важно, что не может быть конструктор.

Если есть надобность в написании конструктора для унаследованного класса, надо знать ещё одну тонкость: необходим вызов конструктора прямого базового класса. Реализуется это несложно:

Конструктор прямого базового класса вызывается в списке инициализации с необходимыми параметрами. Для упрощения данные конструкторы не имеют параметров.

Аналогично конструктору, в классе можно описать ещё одну специфическую функцию – деструктор .

Деструктор – класса, вызывающаяся при удалении объекта. Этот метод не имеет параметров и возвращаемого значения. Если его не указывать явно, то компилятор предоставит стандартный деструктор, как и конструктор. Если есть необходимость указать явный деструктор, это можно сделать так:

Прототип у деструктора почти такой жекак и у конструктора, он именуется именем класса и предваряется «~». Деструктор вызывается при вызове оператора delete или при любом другом удалении объекта.

Деструктор может быть виртуальным, тогда его поведение ничем не отличается от поведения обычной виртуальной функции и подчиняется тем же правилам.

Пользу ООП можно продемонстрировать на следующем примере.

Допустим, у нас есть количество яблок и груш и нам нужно работать со всеми этими фруктами, тогда мы можем представить это в виде массива фруктов. Код ниже демонстрирует сказанное:

Таким образом, мы имеем массив указателей из тысячи элементов на тип Fruit , далее для каждого из них выделяем память под тот фрукт, который нужен: яблоко или грушу. Это позволяет теперь пройти циклом по всему массиву и у каждого элемента вызвать метод grow() , чтобы каждый фрукт вырос, но мы не вдаёмся в подробности отдельного объекта – объект сам решает для себя, что он будет делать при вызове функции. На плечах программиста, таким образом, лежит совсем другая задача управления этими объектами.
Прокошев ™ Inc.

Объектно-ориентированное программирование

Python имеет множество встроенных типов, например, int, str и так далее, которые мы можем использовать в программе. Но также Python позволяет определять собственные типы с помощью классов . Класс представляет некоторую сущность. Конкретным воплощением класса является объект.

Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке, у которого есть имя, возраст, какие-то другие характеристики Человек может выполнять некоторые действия — ходить, бегать, думать и т.д. То есть это представление, которое включает набор характеристик и действий, можно назвать классом. Конкретное воплощение этого шаблона может отличаться, например, одни люди имеют одно имя, другие — другое имя. И реально существующий человек будет представлять объект этого класса.

Класс определяется с помощью ключевого слова class :

class название_класса: атрибуты_класса методы_класса

Внутри класса определяются его атрибуты, которые хранят различные характеристики класса, и методы — функции класса.

Создадим простейший класс:

class Person: pass

В данном случае определен класс Person, который условно представляет человека. В данном случае в классе не определяется никаких методов или атрибутов. Однако поскольку в нем должно быть что-то определено, то в качестве заменителя функционала класса применяется оператор pass . Этот оператор применяется, когда синтаксически необходимо определить некоторый код, однако мы не хотим его, и вместо конкретного кода вставляем оператор pass.

После создания класса можно определить объекты этого класса. Например:

class Person: pass tom = Person() # определение объекта tom bob = Person() # определение объекта bob

После определения класса Person создаются два объекта класса Person — tom и bob. Для создания объекта применяется специальная функция — конструктор , которая называется по имени класса и которая возвращает объект класса. То есть в данном случае вызов Person() представляет вызов конструктора. Каждый класс по умолчанию имеет конструктор без параметров:

tom = Person() # Person() - вызов конструктора, который возвращает объект класса Person

Методы классов

Методы класса фактически представляют функции, которые определенны внутри класса и которые определяют его поведение. Например, определим класс Person с одним методом:

class Person: # определение класса Person def say_hello(self): print("Hello") tom = Person() tom.say_hello() # Hello

Здесь определен метод say_hello() , который условно выполняет приветствие — выводит строку на консоль. При определении методов любого класса следует учитывать, что все они должны принимать в качестве первого параметра ссылку на текущий объект, который согласно условностям называется self . Через эту ссылку внутри класса мы можем обратиться к функциональности текущего объекта. Но при самом вызове метода этот параметр не учитывается.

Используя имя объекта, мы можем обратиться к его методам. Для обращения к методам применяется нотация точки — после имени объекта ставится точка и после нее идет вызов метода:

объект.метод([параметры метода])

Например, обращение к методу say_hello() для вывода приветствия на консоль:

tom.say_hello() # Hello

В итоге данная программа выведет на консоль строку «Hello».

Если метод должен принимать другие параметры, то они определяются после параметра self , и при вызове подобного метода для них необходимо передать значения:

class Person: # определение класса Person def say(self, message): # метод print(message) tom = Person() tom.say("Hello METANIT.COM") # Hello METANIT.COM

Здесь определен метод say() . Он принимает два параметра: self и message. И для второго параметра — message при вызове метода необходимо передать значение.

self

Через ключевое слово self можно обращаться внутри класса к функциональности текущего объекта:

self.атрибут # обращение к атрибуту self.метод # обращение к методу

Например, определим два метода в классе Person:

class Person: def say(self, message): print(message) def say_hello(self): self.say("Hello work") # обращаемся к выше определенному методу say tom = Person() tom.say_hello() # Hello work

Здесь в одном методе — say_hello() вызывается другой метод — say() :

self.say("Hello work")

Поскольку метод say() принимает кроме self еще параметры (параметр message), то при вызове метода для этого параметра передается значение.

Причем при вызове метода объекта нам обязательно необходимо использовать слово self , если мы его не используем:

def say_hello(self): say("Hello work") # ! Ошибка

То мы столкнемся с ошибкой

Конструкторы

Для создания объекта класса используется конструктор. Так, выше когда мы создавали объекты класса Person, мы использовали конструктор по умолчанию, который не принимает параметров и который неявно имеют все классы:

tom = Person()

Однако мы можем явным образом определить в классах конструктор с помощью специального метода, который называется __init__() (по два прочерка с каждой стороны). К примеру, изменим класс Person, добавив в него конструктор:

class Person: # конструктор def __init__(self): print("Создание объекта Person") def say_hello(self): print("Hello") tom = Person() # Создание объекта Person tom.say_hello() # Hello

Итак, здесь в коде класса Person определен конструктор и метод say_hello() . В качестве первого параметра конструктор, как и методы, также принимает ссылку на текущий объект — self. Обычно конструкторы применяются для определения действий, которые должны производиться при создании объекта.

Теперь при создании объекта:

tom = Person()

будет производится вызов конструктора __init__() из класса Person, который выведет на консоль строку «Создание объекта Person».

Атрибуты объекта

Атрибуты хранят состояние объекта. Для определения и установки атрибутов внутри класса можно применять слово self . Например, определим следующий класс Person:

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека tom = Person("Tom") # обращение к атрибутам # получение значений print(tom.name) # Tom print(tom.age) # 1 # изменение значения tom.age = 37 print(tom.age) # 37

Теперь конструктор класса Person принимает еще один параметр — name. Через этот параметр в конструктор будет передаваться имя создаваемого человека.

Внутри конструктора устанавливаются два атрибута — name и age (условно имя и возраст человека):

def __init__(self, name): self.name = name self.age = 1

Атрибуту self.name присваивается значение переменной name. Атрибут age получает значение 1.

Если мы определили в классе конструктор __init__, мы уже не сможем вызвать конструктор по умолчанию. Теперь нам надо вызывать наш явным образом опреледеленный конструктор __init__, в который необходимо передать значение для параметра name:

tom = Person("Tom")

Далее по имени объекта мы можем обращаться к атрибутам объекта — получать и изменять их значения:

print(tom.name) # получение значения атрибута name tom.age = 37 # изменение значения атрибута age

В принципе нам необязательно определять атрибуты внутри класса — Python позволяет сделать это динамически вне кода:

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека tom = Person("Tom") tom.company = "Microsoft" print(tom.company) # Microsoft

Здесь динамически устанавливается атрибут company, который хранит место работы человека. И после установки мы также можем получить его значение. В то же время подобное определение чревато ошибками. Например, если мы попытаемся обратиться к атрибуту до его определения, то программа сгенерирует ошибку:

tom = Person("Tom") print(tom.company) # ! Ошибка - AttributeError: Person object has no attribute company

Для обращения к атрибутам объекта внутри класса в его методах также применяется слово self:

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom") tom.display_info() # Name: Tom Age: 1

Здесь определяется метод display_info(), который выводит информацию на консоль. И для обращения в методе к атрибутам объекта применяется слово self: self.name и self.age

Создание объектов

Выше создавался один объект. Но подобным образом можно создавать и другие объекты класса:

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom") tom.age = 37 tom.display_info() # Name: Tom Age: 37 bob = Person("Bob") bob.age = 41 bob.display_info() # Name: Bob Age: 41

Здесь создаются два объекта класса Person: tom и bob. Они соответствуют определению класса Person, имеют одинаковый набор атрибутов и методов, однако их состояние будет отличаться.

При выполнении программы Python динамически будет определять self — он представляет объект, у которого вызывается метод. Например, в строке:

tom.display_info() # Name: Tom Age: 37

Это будет объект tom

bob.display_info()

Это будет объект bob

В итоге мы получим следующий консольный вывод:

Name: Tom Age: 37 Name: Bob Age: 41

Объекты и классы в Python: объясняем предельно просто

Суть объектно-ориентированного программирования (ООП) очевидно раскрывается в его названии. Эта парадигма предлагает представлять все компоненты программы как объекты из реальной жизни. У каждого такого объекта есть характеристики и он выполняет определенные функции.

Професійний курс від mate.academy: Java.
Погрузьтеся у світ програмування.

Например, объект может представлять собой человека с такими характеристиками, как имя, возраст и род занятий, а также поведением, таким как ходьба, разговор и бег. Это Дима, ему 18 лет, он спортсмен и сейчас бегает по стадиону, а когда устанет, будет ходить и разговаривать с тренером о том, как повысить выносливость.

Python — язык с удобной, продуманной объектной моделью. Поэтому использовать эту парадигму на нем приятно. Давайте познакомимся с основными понятиями ООП Python.

Если самостоятельно не получается освоить язык Python, то лучше поискать хорошие курсы. Мы можем посоветовать проверенные курсы от наших друзей школы Mate Academy, Powercode, Hillel.

Объекты и классы в Python

1. Принципы ООП

Основные принципы ООП включают абстракцию, инкапсуляцию, наследование и полиморфизм. Есть также объекты и классы. Вместе они составляют принцип работы любого объектно-ориентированного языка программирования, в том числе Python.

Ефективний курс від laba: Фінансовий менеджер.
Оптимізуйте фінансовий розвиток компанії.

Инкапсуляция

Инкапсуляция — это набор свойств и методов одного класса или объекта.

Программы могут быть очень длинными, в них может быть тонна движущихся частей. Через некоторое время становится трудно поддерживать все эти объекты, не создавая при этом сложности.

Чтобы управлять кодом было удобнее (и безопаснее), придумали инкапсуляцию. Это принцип, который призывает блокировать доступ к деталям сложных концепций.

Инкапсуляция позволяет скрыть конкретную информацию и контролировать доступ к внутреннему состоянию объекта. Общая идея этого механизма проста. Например, у вас есть атрибут, который не виден снаружи объекта. Вы связываете его с методами, обеспечивающими доступ для чтения или записи.

Абстракция

Если вы пьете кофе, то есть большая вероятность, что вы использовали кофемашину. Вы знаете, что кофемашина готовит кофе. Но вам не нужно знать, как она делает кофе. Все, что вам нужно знать, — какие кнопки нажимать, чтобы приготовить кофе. Вы используете интерфейс, определяемый кнопками, не беспокоясь о внутренней работе машины.

Рассматривайте метод как кофеварку, а ваш входной параметр — как кнопки на машине. Абстракция позволяет создавать бесшовные программы, просто зная, какой метод вызывать и какие параметры вводить.

Полиморфизм

Полиморфизм — способность одной функции выполняться по-разному. Это позволяет создавать несколько реализаций одной идеи. Например, вы делаете компьютерную игру. В ней есть класс «Транспорт» с методом «Двигаться». После выполнения метода самолет должен полететь, автомобиль — поехать, а корабль — поплыть. Все три действия — это движение, но реализованы они будут по-разному.

Полиморфизм можно применять двумя способами:

    перегрузка метода (статический полиморфизм);

Творчий курс від skvot: 3D-художник персонажів.
Створюйте світ персонажів.

Когда класс имеет несколько методов с одинаковыми именами, но с другим набором параметров, это называется перегрузкой методов. Вы можете продолжить перегрузку метода, только если ваши методы удовлетворяют любому из следующих правил:

  • имеет разные параметры;
  • имеет разные типы возврата;

Второй способ полиморфизма — переопределение методов. Это возможно только в том случае, если с подкласс или родственный класс имеет тот же метод, что и родительский класс. Как и при перегрузке метода, существуют некоторые правила работы переопределения метода:

  • имеет тот же список параметров;
  • имеет тот же тип возврата;
  • имеет модификатор доступа, более строгий, чем у родительского класса.

Наследование

Наследование — возможность приобретать свойства существующих классов и создавать новые. Этот принцип призывает повторно использовать код без необходимости переписывать его в программе.

Інтенсивний курс від skvot: Ретуш фотографій.
Перетворіть свої знімки у шедеври.

Вернемся к аналогии с компьютерной игрой. У вас есть абстракция «Транспорт». На этом уровне вы не учитывает характеристики каждого объекта: самолета, автомобиля, корабля.

Если приглядеться к объектам, то становится ясно, что у них есть характеристики, которые совпадают и которые различаются. Например, у самолета важен размах крыльев, а у автомобиля и корабля их вообще нет. При этом у самолета, автомобиля и корабля есть характеристика года выпуска или цвета.

Наследование позволяет сделать отдельный класс «Самолет», который будет наследником класса «Транспорт». Он сохраняет атрибуты класса «Транспорт» (год выпуска, цвет), но при этом получает новые — размах крыльев.

2. Класс

Объектно ориентированное программирование Python, как и других языков, основано на двух важных концепциях — классах и объектах.

Класс — это схема того, как что-то должно быть определено. На самом деле он не содержит никаких данных. Класс Cat указывает, что для определения кошки необходимы имя и возраст. Но он не содержит имя или возраст какой-либо конкретной кошки.

Как в Python создать класс

Создать класс очень просто. Достаточно написать инструкцию class и добавить имя.

class FirstClass: pass

Для именования классов в Python используют нотацию CamelCase — каждое слово начинается с заглавной буквы.

В примере выше тело класса состоит из одного оператора pass. Он нужен для того, чтобы интерпретатор Python не выдавал ошибку. Фактически это пустой класс, у которого нет ни атрибутов (характеристик), ни методов. Давайте их добавим.

Добавление методов и атрибутов

Конструктор — это метод, который вызывается при создании классов. Благодаря ему у объектов изначально есть какие-то значения.

Например, на основании класса Cat можно создать объекты c именами Milo и Simba, а также возрастом — 2 и 3 года.

Создание объектов рассмотрим чуть позже, а пока вернемся к конструкторам.

В Python конструктором является метод __init__() . В нем указываются все свойства, которыми должны обладать объекты класса Cat. Каждый раз, когда создается новый объект Cat , __init__() устанавливает начальное состояние, присваивая свойствам значения. То есть __init__() инициализирует каждый новый экземпляр класса.

Вы можете указать в __init__() любое количество параметров, но первым параметром всегда будет переменная с именем self . Когда создается новый экземпляр класса, он автоматически передается self параметру в __init__(), чтобы можно было определить новые атрибуты объекта.

Важно: self — не зарезервированное имя. У первого параметра при инициализации может быть и другое название. Однако есть соглашение, что его называют self. Это помогает унифицировать создание классов в разных проектах.

class Cat: def __init__(self, name, age): self.name = name self.age = age

В теле __init__() есть два оператора, использующих переменную self:

  • self.name = name создает атрибут с именем name и присваивает ему значение параметра name .
  • self.age = age создает атрибут с именем age и присваивает ему значение параметра age.

Важно соблюдать отступы. Они показывают, что метод __init__ принадлежит классу Cat, а атрибуты self.name и self.age принадлежат методу __init__.

Атрибуты экземпляра и атрибуты класса

Атрибуты, созданные в __init__(), называются атрибутами экземпляра. Их значения зависят от конкретного экземпляра класса. У всех объектов есть имя и возраст. Но значения атрибутов name и age будут различаться в зависимости от объекта.

Чтобы не запутаться, давайте посмотрим примеры. Вернемся к нашему классу Cat. Вот он:

class Cat: def __init__(self, name, age): self.name = name self.age = age

Создадим на его основе два объекта — экземпляра класса Cat. Первый объект — кошка Milo. Ей два года. Второй объект — кошка Simba, ей три года. У обоих объектов есть имя и возраст. Но значения у них разные. Это достигается благодаря ключевому слову self .

Self — указатель на текущий экземпляр класса. Он позволяет работать с отдельными объектами, а не всеми экземплярами, которые принадлежат классу. Благодаря self мы можем указать, что одну кошку зовут Milo, а вторую — Simba, что одной кошке — два года, а другой — три года.

Кроме атрибутов экземпляра существуют атрибуты класса. Они имеют одинаковое значение для всех объектов. Вы можете определить атрибут класса, присвоив значение имени переменной за пределами метода __init__().

class Cat: # Class attribute cute = "Cat is so cute" def __init__(self, name, age): self.name = name self.age = age

Атрибуты класса определяются под первой строкой имени класса и имеют отступ в четыре пробела. Им всегда должно быть присвоено начальное значение. При создании экземпляра класса автоматически создаются атрибуты класса, которым присваиваются их начальные значения.

Теперь вы можете создать двух кошек с разными именами и возрастом. Но их будет объединять атрибут класса cute — обе они милые. Этот атрибут класса будет появляться во всех экземплярах класса, которые вы будете создавать.

Важно:

Используйте атрибуты класса для определения свойств, которые должны иметь одинаковое значение для каждого экземпляра класса. Используйте атрибуты экземпляра для свойств, которые меняются от одного экземпляра к другому.

Методы

Кроме __init__() могут быть и другие методы. Они делятся на три группы:

  • методы экземпляра класса;
  • методы класса;
  • статические методы.

Чтобы лучше понять разницу между ними, посмотрим пример:

class MyClass: def method(self): return 'instance method called', self @classmethod def classmethod(cls): return 'class method called', cls @staticmethod def staticmethod(): return 'static method called'

В этом классе есть все три метода. Первый — метод экземпляра класса. Он принимает параметр self , но, как вы видели выше на примере атрибутов, ему можно передавать любые другие параметры.

Методы экземпляра класса — самые распространенные, обычно приходится работать именно с ними.

class Cat: def __init__(self, name, age): self.name = name self.age = age

Благодаря параметру self методы экземпляра класса имеют доступ к атрибутам и методам объектов. Это позволяет изменять состояние объектов.

Второй тип — метод класса. В примере выше он определен с помощью декоратора @classmethod. Декораторы — это обертки, которые позволяют менять назначение функций.

Методы класса принимают параметр cls. При вызове метода этот параметр указывает не на объект, а на сам класс. Такие методы не могут менять объекты по отдельности — как вы теперь знаете, для этого нужен параметр self. Но они могут менять состояние класса в целом, что влияет на все объекты этого класса.

Пример метода класса:

class Cat: def speak(cls): print('Мяу!')

Теперь вы можете создать экземпляры этого класса — конкретных кошек. Все они будут уметь говорить «Мяу».

Если вы измените метод класса, то это модифицирует всех кошек. Например:

class Cat: def speak(cls): print('Гав!')

Теперь все кошки будут лаять, а не мяукать. Пожалуй, лучше вернуть все как было.

Статический метод определен с помощью декоратора @staticmethod. Он принимает любые параметры в любых количествах, кроме self и cls. Статические методы не меняют состояние ни класса, ни объекта. Они помещаются в класс для того, чтобы быть в пространстве имен, их используют для организационных целей.

3. Объекты или экземпляры класса

Чем объекты отличаются от классов

В то время как класс является планом (схемой, чертежом — можно использовать разные сравнения), экземпляр представляет собой объект, созданный из класса и содержащий реальные данные. Экземпляр класса Cat — это уже не схема. Это настоящая кошка с именем и возрастом.

Класс похож на форму или анкету. Экземпляр подобен форме, которая была заполнена информацией. Подобно тому, как многие люди могут заполнять одну и ту же форму со своей собственной уникальной информацией, многие экземпляры могут быть созданы из одного класса.

Как создать объект класса в Python

Сначала нужно создать класс. На его основе вы будете создавать объекты — разные экземпляры класса.

Допустим, есть класс Cat. В нем определены параметры, которые должны быть у каждого объекта этого класса.

class Cat: cute = "Cat is so cute" def __init__(self, name, age): self.name = name self.age = age

Чтобы создать два объекта, достаточно передать имя и возраст — параметры, которые указаны в классе.

milo = Cat("Milo", 2) simba = Cat("Simba", 3)

Если в классе заданы параметры, а при создании объекта вы их не передаете, то вылезет ошибка. Например, вот этот код в данном случае не сработает:

milo = Cat()

В ответ появится сообщение об ошибке:

TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'

Чтобы исправить ошибку, достаточно указать в круглых скобках имя и возраст. Тогда новый объект будет инициализирован корректно.

Есть и неочевидный момент. Метод класса __init__() имеет три параметра. Почему же в примере ему передаются только два аргумента? Никакой магии нет. Когда вы создаете экземпляр объекта, Python создает новый объект и передает его первому параметру __init__(). Это по существу удаляет self, поэтому вам нужно беспокоиться только о параметрах name и age.

После создания экземпляров вы можете получить доступ к их атрибутам, используя запись через точку. Например:

milo.name Output: “Milo” simba.age Output: 3

Аналогичным образом можно получить доступ к атрибутам класса, так как они применяются ко всем объектам.

milo.cute Output: "Cat is so cute"

Одним из самых больших преимуществ использования классов для организации данных является предсказуемость. Все экземпляры класса Cat имеют атрибуты .cute, .name .age , поэтому вы можете уверенно их использовать, зная, что они всегда будут возвращать значение.

При этом атрибуты можно менять динамически. Например:

milo.age = 4 milo.age Output: 4

Ключевым выводом здесь является то, что пользовательские объекты по умолчанию изменяемы.

Заключение

Мы рассмотрели основы объектно-ориентированного программирования в Python. Теперь вы знаете основные принципы и умеете создавать классы и объекты. Чтобы закрепить знания, посмотрите это видео про объектно-ориентированное программирование:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *