Объектно-ориентированное программирование. Классы и объекты
Сегодня мы поговорим об объектно-ориентированном программировании и о его применении в python.
Объектно-ориентированное программирование (ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов.
Класс — тип, описывающий устройство объектов. Объект — это экземпляр класса. Класс можно сравнить с чертежом, по которому создаются объекты.
Python соответствует принципам объектно-ориентированного программирования. В python всё является объектами — и строки, и списки, и словари, и всё остальное.
Но возможности ООП в python этим не ограничены. Программист может написать свой тип данных (класс), определить в нём свои методы.
Это не является обязательным — мы можем пользоваться только встроенными объектами. Однако ООП полезно при долгосрочной разработке программы несколькими людьми, так как упрощает понимание кода.
Приступим теперь собственно к написанию своих классов на python.
>>> # Пример простейшего класса, который ничего не делает ... class A: ... pass
Теперь мы можем создать несколько экземпляров этого класса:
>>> a = A() >>> b = A() >>> a.arg = 1 # у экземпляра a появился атрибут arg, равный 1 >>> b.arg = 2 # а у экземпляра b - атрибут arg, равный 2 >>> print(a.arg) 1 >>> print(b.arg) 2 >>> c = A() >>> print(c.arg) # а у этого экземпляра нет arg Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'A' object has no attribute 'arg'
Классу возможно задать собственные методы:
>>> class A: ... def g(self): # self - обязательный аргумент, содержащий в себе экземпляр ... # класса, передающийся при вызове метода, ... # поэтому этот аргумент должен присутствовать ... # во всех методах класса. ... return 'hello world' ... >>> a = A() >>> a.g() 'hello world'
И напоследок еще один пример:
>>> class B: ... arg = 'Python' # Все экземпляры этого класса будут иметь атрибут arg, ... # равный "Python" ... # Но впоследствии мы его можем изменить ... def g(self): ... return self.arg ... >>> b = B() >>> b.g() 'Python' >>> B.g(b) 'Python' >>> b.arg = 'spam' >>> b.g() 'spam'
Объектно-ориентированное программирование на Python. Курс
Курс «Объектно-ориентированное программирование на Python» знакомит с особенностями ООП в общем и его реализацией в языке Python. Предполагается, что вы знакомы с Python на уровне структурного программирования (основные типы данных, ветвления, циклы, функции).
Ключевыми понятиями объектно-ориентированного программирования являются «класс» и «объект». Это реально существующие в программном коде единицы, а не только обобщающие понятия. Объекты порождаются от своих классов. В языке программирования Python такие объекты принято называть экземплярами.
Наследование, полиморфизм и инкапсуляция – основные принципы, столпы объектно-ориентированного программирования. Наследование предполагает возможность определения дочерних классов, полиморфизм – разный способ реализации одного и того же, инкапсуляция – сокрытие и объединение данных и методов. Композиция реализуется реже, означает возможность создания объектов, составными частями которых являются объекты других классов.
Конструктором в ООП называют метод класса, который вызывается автоматически при создании объекта от этого класса. В то же время конструктор относится к методам перегрузки операторов. Имена таких методов регламентированы самим языком программирования, а их вызов происходит автоматически при участии объекта в тех или иных операциях. Например, сложении, извлечении элемента и др.
Итераторы – это особая разновидность объектов подобных коллекциям вроде списка, но которые не хранят в себе весь набор элементов, а генерируют только один при каждом обращении. В Python есть встроенные классы-типы данных, от которых создаются итераторы. Однако также можно определять собственные классы, чьи экземпляры будут обладать возможностями итераторов.
Курс включает 12 основных уроков + 3 дополнительных:
Что такое объектно-ориентированное программирование
Создание классов и объектов
Конструктор класса – метод __init__()
Наследование
Полиморфизм
Инкапсуляция
Композиция
Перегрузка операторов
Модули и пакеты
Документирование кода
Пример объектно-ориентированной программы на Python
Особенности объектно-ориентированного программирования
Статические методы
Итераторы
Генераторы
Курс с примерами решений практических работ и всеми уроками:
android-приложение, pdf-версия
Версия курса: октябрь 2020.
Классы в Python 3 и объекты — примеры наследования и что означает self
Классы в языке Python являются важнейшей частью объектно-ориентированного подхода к программированию. Класс описывает пользовательский тип данных, на основе которого в программе создаются однородные объекты. Как правило, они могут включать в себя некие свойства и методы, позволяющие реализовать их текущее состояние, а также поведение. В статье описаны классы для начинающих и чайников в Python 3, а так же чтобы освежить знания опытным программистам.
Объектно-ориентированное программирование
Объектно-ориентированный подход к разработке ПО был призван стать надежной заменой для структурной методологии программирования. Согласно этой уже устаревшей концепции, каждая отдельно взятая программа является иерархической структурой из функциональных блоков кода.
В свою очередь, ООП предлагает несколько иной способ реализации программ, представляя их в виде совокупности объектов, взаимодействующих между собой.
Благодаря такой особенности:
- Улучшается восприятие поставленной задачи при работе над проектом;
- Сокращается количество строк кода;
- Уменьшается сложность написания кода.
Основными принципами ООП являются следующие механизмы: абстракция, инкапсуляция, наследование и полиморфизм. Для создания программ, обрабатывающих информацию в виде объектов, необходимо понимание, а также комплексное соблюдение всех четырех парадигм. Практическое применение каждой из них можно встретить в примерах из данной статьи.
Рассмотрим основные принципы ООП:
- Абстракция выполняет основную задачу ООП, позволяя программисту формировать объекты определенного типа с различными характеристиками и поведением, благодаря применению классов.
- Инкапсуляция помогает скрыть детали реализации конкретных объектов и защитить их свойства от постороннего вмешательства.
- Наследование дает возможность расширять уже существующие классы за счет автоматического переноса их параметров и методов к новым структурам данных.
- Полиморфизм используется для создания единого интерфейса, который имеет множество различных реализаций, зависящих от класса применяемого объекта.
Создание класса и объекта
Чтобы определить новый класс в своей программе, необходимо напечатать ключевое слово class, а после него добавить имя для создаваемой структуры данных, завершив ввод вставкой двоеточия. Следующий пример демонстрирует генерацию пустого класса с именем Example. Как можно заметить, в нем полностью отсутствует какая-либо информация.
class Example: pass example = Example()
Несмотря на пустое тело класса Example, на его основе уже можно создать определенный объект, обладающий уникальным идентификатором. Последняя строка кода, находящегося выше, представляет собой пример генерации объекта с именем example и типом данных Example. Здесь используется оператор присваивания, а также пустые круглые скобки после названия класса, прямо как в вызове метода не имеющего никаких аргументов.
Определив новый класс, можно создавать сколько угодно объектов на его основе. Как уже было сказано выше, такая структура данных может включать в себя некие свойства, то есть переменные, которыми будет наделен каждый экземпляр класса. Ниже приведен простой пример класса и объекта Python 3. В примере описывается класс под названием Data со строкой word и числом number.
class Data: word = "Python" number = 3 data = Data() print(data.word + " " + str(data.number)) Python 3
Если создать объект, основанный на классе Data, то он получит обе переменные, а также их значения, которые были определены изначально. Таким образом, был сгенерирован объект data. Получить доступ к его полям с именами word и number можно с помощью оператора точки, вызвав его через экземпляр класса. Функция print поможет вывести значения полей объекта data на экран. Не стоит забывать и о том, что число следует привести к строчному виду для того чтобы обработать его в методе print вместе с текстовым значением.
Помимо полей, пользовательский класс может включать в себя и методы, которыми будут наделены все его экземпляры. Вызвать выполнение определенного метода через созданный объект можно так же, как и получить доступ к его полям, то есть с помощью точки. Данный пример демонстрирует класс Data с функцией sayHello, которая выводит текст на экран.
class Data: def sayHello(self): print("Hello World!") data = Data() data.sayHello() Hello World!
Для того чтобы вызвать метод sayHello, нужно создать объект, принадлежащий требуемому классу Data. После этого можно запустить функцию через сгенерированный экземпляр с идентификатором data, что позволит вывести небольшое текстовое сообщение.
Аргумент self
Рассмотрим зачем нужен и что означает self в функциях Python. Как можно было заметить, единственным атрибутом для метода из класса является ключевое слово self. Помещать его нужно в каждую функцию чтобы иметь возможность вызвать ее на текущем объекте.
class Dog: name = "Charlie" noise = "Woof!" def makeNoise(self): print(self.name + " says: " + self.noise + " " + self.noise) dog = Dog() dog.makeNoise() Charlie says: Woof! Woof!
Вверху представлен класс Dog, описывающий собаку. Он обладает полями name (имя) со стартовым значением «Charlie» и noise (шум), содержащим звук, который издает животное. Метод makeNoise заставляет собаку лаять, выдавая соответствующее сообщение на экран. Для этого в функции print используется получение доступа к полям name и noise. Далее необходимо создать экземпляр класса Dog и вызвать на нем makeNoise.
Конструктор
В предыдущих примерах кода все создаваемые объекты получали значения для своих полей напрямую из класса, так как они были заданы по умолчанию. Изменить внутренние данные любого объекта можно с помощью оператора доступа к свойствам объекта. Но существует возможность заранее определить поля для объекта, задав их во время его создания. Для этой цели в ООП используется конструктор, принимающий необходимые параметры. Следующий пример показывает работу конструктора во время инициализации объекта класса Dog.
class Dog: def __init__(self, name, breed): self.name = name self.breed = breed dog = Dog("Max", "German Shepherd") print(dog.name + " is "+ dog.breed) Max is German Shepherd
Внешне конструктор похож на обычный метод, однако вызвать его явным образом нельзя. Вместо этого он автоматически срабатывает каждый раз, когда программа создает новый объект для класса, в котором он расположен. Имя у каждого конструктора задается в виде идентификатора __init__. Получаемые им параметры можно присвоить полям будущего объекта, воспользовавшись ключевым словом self, как в вышеописанном примере.
Таким образом, класс Dog содержит два поля: name (имя) и breed (порода). Конструктор принимает параметры для изменения этих свойств во время инициализации нового объекта под названием dog. Каждый класс содержит в себе по крайней мере один конструктор, если ни одного из них не было задано явно. Однако в том случае, когда программист добавляет в свой класс конструктор с некими параметрами, конструктор, не обладающий параметрами, работать не будет. Чтобы им воспользоваться, нужно явно прописать его в классе.
Ключевой особенностью ООП является абстракция, благодаря которой есть возможность создавать частные объекты на основе общего класса, то есть определенного абстрактного понятия, такого как собака, поскольку она может иметь свое имя, породу, вес, рост.
Деструктор
Работа с деструктором, как правило, является прерогативой языков, предоставляющих более широкие возможности для управления памятью. Несмотря на грамотную работу сборщика мусора, обеспечивающего своевременное удаление ненужных объектов, вызов деструктора все еще остается доступным. Переопределить его можно в классе, задав имя __del__.
class Data: def __del__(self): print "The object is destroyed" data = Data() del(data) The object is destroyed
Как и конструктор, деструктор может содержать некий пользовательский код, сообщающий об успешном завершении работы метода. В данном примере создается экземпляр класса Data и вызывается его деструктор, принимающий в качестве параметра сам объект.
Наследование
Возможность одному классу выступать в качестве наследника для другого, перенимая тем самым его свойства и методы, является важной особенностью ООП.
Благодаря этой важной особенности пропадает необходимость переписывания кода для подобных по назначению классов.
При наследовании классов в Python обязательно следует соблюдать одно условие: класс-наследник должен представлять собой более частный случай класса-родителя. В следующем примере показывается как класс Person (Человек) наследуется классом Worker (Работник). При описании подкласса в Python, имя родительского класса записывается в круглых скобках.
class Person: name = "John" class Worker(Person): wage = 2000 human = Worker() print(human.name + " earns $" + str(human.wage)) John earns $2000
Person содержит поле name (имя), которое передается классу Worker, имеющему свойство wage (заработная плата). Все условия наследования соблюдены, так как работник является человеком и также обладает именем. Теперь, создав экземпляр класса Worker под названием human, можно получить свободный доступ к полям из родительской структуры данных.
Множественное наследование
Наследовать можно не только один класс, но и несколько одновременно, обретая тем самым их свойства и методы. В данном примере класс Dog (Собака) выступает в роли подкласса для Animal (Животное) и Pet (Питомец), поскольку может являться и тем, и другим. От Animal Dog получает способность спать (метод sleep), в то время как Pet дает возможность играть с хозяином (метод play). В свою очередь, оба родительских класса унаследовали поле name от Creature (Создание). Класс Dog также получил это свойство и может его использовать.
class Creature: def __init__(self, name): self.name = name class Animal(Creature): def sleep(self): print(self.name + " is sleeping") class Pet(Creature): def play(self): print(self.name + " is playing") class Dog(Animal, Pet): def bark(self): print(self.name + " is barking") beast = Dog("Buddy") beast.sleep() beast.play() beast.bark() Buddy is sleeping Buddy is playing Buddy is barking
В вышеописанном примере создается объект класса Dog, получающий имя в конструкторе. Затем по очереди выполняются методы sleep (спать), play (играть) и bark (лаять), двое из которых были унаследованы. Способность лаять является уникальной особенностью собаки, поскольку не каждое животное или домашний питомец умеет это делать.
Абстрактные методы
Поскольку в ООП присутствует возможность наследовать поведение родительского класса, иногда возникает необходимость в специфической реализации соответствующих методов. В качестве примера можно привести следующий код, где классы Dog (Собака) и Cat (Кошка) являются потомками класса Animal (Животное). Как и положено, они оба наследуют метод makeNoise (шуметь), однако в родительском классе для него не существует реализации.
Все потому, что животное представляет собой абстрактное понятие, а значит не способно издавать какой-то конкретный звук. Однако для собаки и кошки данная команда зачастую имеет общепринятое значение. В таком случае можно утверждать, что метод makeNoise из Animal является абстрактным, поскольку не имеет собственного тела реализации.
class Animal: def __init__(self, name): self.name = name def makeNoise(self): pass class Dog(Animal): def makeNoise(self): print(self. name + " says: Woof!") class Cat(Animal): def makeNoise(self): print(self.name + " says: Meow!") dog = Dog("Baxter") cat = Cat("Oliver") dog.makeNoise() cat.makeNoise() Baxter says: Woof! Oliver says: Meow!
Как видно из примера, потомки Dog и Cat получают makeNoise, после чего переопределяют его каждый по-своему. В этом заключается суть полиморфизма, позволяющего изменять ход работы определенного метода исходя из нужд конкретного класса. При этом название у него остается общим для всех наследников, что помогает избежать путаницы с именами.
Статические методы
В предыдущих примерах все методы классов вызывались при помощи объектов, имеющих соответствующий тип. Однако пользоваться таким подходом неудобно, когда в программе нет нужды в обращении к каким-либо специфическим свойствам класса. К примеру, есть определенная структура Math, содержащая в себе методы для арифметических вычислений. Применять ее функции можно не создавая объект, если они помечены, как статические. Для того, чтобы отметить в классе метод как статический, в Python используется декоратор @staticmethod
.
class Math: @staticmethod def inc(x): return x + 1 @staticmethod def dec(x): return x - 1 print(Math.inc(10), Math.dec(10)) (11, 9)
В вышеописанном коде класс Math включает в себя два статических метода: inc, берущий число в качестве параметра и возвращающий результат, увеличенный на единицу, и dec, делающий все то же самое, только наоборот. Вызвать оба этих метода можно с помощью оператора точки, а также имени класса Math, где они были изначально реализованы.
Ограничение доступа
По умолчанию все свойства классов открыты для доступа извне, благодаря чему их можно в любой момент изменить по своему усмотрению при помощи оператора точки. Это не всегда хорошо, так как существуют некие риски потери информации либо введения неправильных данных, приводящих к сбоям в работе программы. Особенно это опасно, когда над проектом работает несколько программистов и не всегда очевидно, для чего нужно то или иное поле.
В такой ситуации помогает еще одна особенность ООП под названием инкапсуляция. Она предписывает применение приватных свойств класса, к которым отсутствует доступ за его пределами. Для управления содержимым объекта необходимо использовать специальные методы, именуемые getter (возвращает значение) и setter (устанавливает значение).
class Cat: __name = "Kitty" def get_name(self): return self.__name def set_name(self, name): self.__name = name cat = Cat() print(cat.get_name()) cat.set_name("Misty") print(cat.get_name()) Kitty Misty
Чтобы ограничить видимость полей, следует задать для них имя, начинающееся с двойного подчеркивания. В примере, продемонстрированном выше, класс Cat (Кошка) имеет закрытое свойство __name (имя), а также специальные методы get_name и set_name. Отличительной чертой такого подхода является возможность установить определенные рамки для вводимых значений. Например, можно запретить ввод отрицательного числа или пустой строки.
Свойства классов
С помощью специального механизма свойств класса можно внести корректировки в работу с оператором точки, присвоив ему собственные функции. В следующем примере представлен класс с приватным полем x, для которого написаны getter и setter. С помощью присвоения полю x специального значения функции property, получающей в качестве аргументов имена методов, можно настроить работу оператора точки согласно своим нуждам.
class Data: def __init__(self, x): self.__set_x(x) def __get_x(self): print("Get X") return self.__x def __set_x(self, x): self.__x = x print("Set X") x = property(__get_x, __set_x) data = Data(10) print(data.x) data.x = 20 print(data.x) Set X Get X 10 20
Как видно из результатов выполнения кода, методы __get_x и __set_x работают с помощью оператора точки, вызываясь самостоятельно. Таким образом, упрощается написание кода при изменении свойств объекта, а также повышается уровень безопасности данных.
Перегрузка операторов
Для обработки примитивных типов данных в языках программирования используются специальные операторы. К примеру, арифметические операции выполняются при помощи обычных знаков плюс, минус, умножить, разделить. Однако при работе с собственными типами информации вполне может потребоваться помощь этих операторов. Благодаря специальным функциям, их можно самостоятельно настроить под свои задачи.
В данном примере создается класс Point (точка), обладающий двумя полями: x и y. Для сравнения двух разных объектов такого типа можно написать специальный метод либо же просто перегрузить соответствующий оператор. Для этого потребуется переопределить функцию __eq__ в собственном классе, реализовав новое поведение в ее теле.
class Point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): return self. x == other.x and self.y == other.y print(Point(2, 5) == Point(2, 5)) print(Point(3, 8) == Point(4, 6)) True False
Переопределенный метод возвращает результат сравнения двух полей у различных объектов. Благодаря этому появилась возможность сравнивать две разных точки, пользуясь всего лишь обычным оператором. Результат его работы выводится при помощи метода print.
Аналогично сравнению, можно реализовать в Python перегрузку операторов сложения, вычитания и других арифметических и логических действий. Так же можно сделать перегрузку стандартных функций str и len.
Заключение
В данной статье были рассмотрены основные особенности работы с классами в языке Python и наглядно продемонстрированы наиболее важные принципы объектно-ориентированного программирования. Работа с классами позволяет представить все данные в программе в виде взаимодействующих между собой объектов, обладающих некими свойствами и поведением.
#17 — Основы ООП Python
В уроке мы приступим к изучению ООП в языке Python. ООП это объектно ориентированное программирование в основе которого является создание класса, а также объекта класса. Мы научимся создавать классы и объекты, а также создадим методы и поля для основного класса.
На начальном этапе ООП – это тёмный лес, в котором многое непонятно и слишком усложнено. На самом деле всё вовсе не так. Предлагаем абстрагироваться от специфических (непонятных) определений и познакомиться с ООП простыми словами.
ООП простыми словами
Поскольку на примере все усвоить гораздо проще, то давайте за пример возьмем робота, которого постараемся описать за счёт классов в ООП.
Класс в случае с роботом – это его чертёж. Экземпляром класса (объектом) называет целый робот, который создан точно по чертежу.
Наследование – это добавление полезных опций к чертежу робота. К примеру, берем стандартный чертёж робота и дорисуем к нему лазеры, крылья и броню. Все эти дорисовки мы сделаем в классе наследнике, основной функционал которого взят из родительского класса.
Полиморфизм – это общий функционал для всех роботов и не важно что каждый робот может очень сильно отличаться друг от друга. К примеру, в главном классе мы указываем возможность передвижения для всех последующих роботов. Далее в классе наследнике мы можем дополнительно указать возможность левитации для робота, в другом же классе укажем возможность передвижения по воде и так далее. Получается, что есть общий функционал что записан в главном чертеже, но его можно переписать для каждого последующего робота (для каждого наследника).
А инкапсуляция является для нас бронёй, защищающей робота. Под пластырем брони находятся уязвимые элементы, вроде проводов и микросхем. После прикрытия брешей с помощью брони (protected
или private
), робот полностью защищён от внешних вмешательств. По сути, мы делаем доступ ко всем полям лишь за счёт методов, тем самым прямой доступ к полю будет закрыт.
У всех классов методы могут отличаться, как и поля с конструкторами. Каждый класс позволяет создавать любое количество разных объектов, все из них имеют собственные характеристики.
Создание классов
Для создания класса необходимо прописать ключевое слово class
и далее название для класса. Общепринято начинать названия классов с буквы в верхнем регистре, но если этого не сделать, то ошибки не будет.
В любом классе можно создавать поля (переменные), методы (функции), а также конструкторы.
Создав новый класс и поместив туда какую-либо информацию мы можем создавать на основе него новые объекты. Объекты будут иметь доступ ко всем характеристикам класса.
Пример простого класса приведен ниже:
class Book:
pass # Класс может ничего не возвращать
На основе такого класса мы можем создать множество объектов. Каждый объект в данном случае будет представлять из себя конкретную книжку. Для каждого объекта мы можем указать уникальные данные.
Чтобы создать объект нам потребуется следующий код:
obj_new = Some() # Создание объекта
obj_second = Some() # Создание 2 объекта
Python — Объектно Ориентированное Программирование (ООП)
В данной статье даются основы ООП в питоне
В python всё — объекты.
*Аудитория в шоке, особо нервные дамочки падают в обморок*- Числа — объекты
- Строки — объекты
- Списки — объекты
- Классы — объекты
- …
Если говорить просто, то «объекты» — это некая структура.
И было слово…
Чтобы создавать объекты, используются «конструкторы» или классы.- Класс — это схема, описывающая нашу структуру, возможные внутри неё данные и присущие ей методы.
- Метод — это функция. Т.е. метод объекта — это функция, описанная внутри объекта, и присущая этому объекту. Метод — это функция, которая действует на объекты данного вида. Для удобства у разных видов объектов могут быть методы с одинаковыми именами, работающие по разному, но схожим образом.
- Экземпляр — это конкретный объект, созданный из класса.
Рассмотрим пример
Список:L = [1, 2, 3, 4]
- Список (List) — это класс объекта
- Переменная L содержит экземпляр объекта (конкретно список [1, 2, 3, 4])
- append(), sort() — методы объекта, т.е. функции, которые можно применить к его экземплярам.
Пока звучит не очень сложно.
Но по прежнему не понятно зачем это нужно. =)
1 что приходит на ум — абстракция. Мы не думаем о том как устроен объект, а думаем о том что мы можем с ним сделать.
Например, возьмём функцию dir() и передадим экземпляр объекта список в неё как аргумент:
dir(L)
На выходе получим большой список. Большой список методов для списка.
У нас есть 2 пути:
- опробовать некоторые из них (возможно, пытаясь передать какие-то атрибуты)
- найти их описание в google по имени
Но в любом случае мы узнаем о том, «что можно делать со списком», не изучая то как он устроен.
При этом если мы создадим свою структуру данных, свой класс со своими объектами, то у них могут быть одноимённые методы (например, если они ведут себя аналогично).
Например, у строк есть несколько методов, одноимённых методом списков:
Метод index() является одним из них.
Рассмотрим как он работает для наших примеров:
Легко заметить, что некоторые методы в списке имели по 2 подчёркивания с обеих сторон, например:
__len__Это «стандартный» метод. Фактически, когда мы используем функцию len(), например:
то на самом деле вызывается метод __len__ соответствующего объекта.
Почему?
Всё потому же — если мы будем внутри функции языка len описывать как вычислять длину любого объекта, то это будет очень много кода. Да и для новых классов объектов (например, numpy.array) эта функция не будет работать.
А так у каждого класса внутри будет краткое описание того как это работает.
Так же это позволяет переопределить поведение некоторых операторов.
Например, что будет, если мы напишем:
Фактически будет вызван метод add — s.__add__(L)
В нашем примере мы получим ошибку:
Но некоторые классы объектов вполне могут принимать на вход «чужака» (не всякого конечно):
А ещё когда мы пишем
print L
, то на самом деле вызывается метод __str__, чтобы преобразовать список L в строку для печати.
Итак,
- класс — это инструкция, по которой собирается конкретный объект
- экземпляр — это конкретный объект
- а метод — это функция, присущая конкретному классу объектов.
И это всё?
Нет. =)
Когда мы говорим, что есть 2 экземпляра объектов список:
то очевидно, что они содержат разные данные.
Т.е. внутри объектов помимо методов есть данные, и хранятся они в атрибутах.
Примером атрибута может быть shape для numpy:
Мы просто создали вектор, передав в него данные. И при этом вычислился его размер.
Логично, для больших матриц в векторов проще хранить внутри 1 переменную с натуральным числом, чем каждый раз проходить по всем данным и тратить время для вычислений.
Давайте попрактикуемся
Создадим пустой класс, который ничего не делает и ничего не хранит:Теперь создадим 1й метод у нашего класса.
Для этого создадим функцию, внутри метода. Она должна принимать по крайней мере 1 аргумент — self — это экземпляр того объекта, методов которого функция будет.
Если мы хотим передавать в метод какие-то параметры, то просто зададим их после self, как и обычные параметры функции:
Это всё здорово, но пока особой разницы между методом и функцией нет.
Можно конечно рассматривать класс как некий контейнер для централизованного хранения функций.
Но обычно всё же класс подразумевает ещё и хранение данных в атрибутах.
Синтаксис для атрибутов аналогичен синтаксису методов (только после атрибута не надо ставить круглые скобки):
Давайте создадим атрибут у экземпляра объекта:
Вполне очевидно, что если я создам 2й экземпляр этого же класса, и присвою уже в нём атрибуту с таким же именем какое-то значение, то у разных экземпляров в одноимённом атрибуте будут разные значения:
Так же я могу определить переменную внутри класса и она станет атрибутов всех экземпляров этого класса.
Естественно, это не отменит возможность принудительного переопределения соответствующего атрибута у какого-то экземпляра:
Для экземпляров B и C значение атрибута равно значению по-умолчанию (списку), а для экземпляров E и A переопределено (на число и строку).
Пока пользоваться классами не очень удобно:
- надо определить класс
- создать объект
- обратиться к каждому из атрибутов, записав туда кастомные данные
- обратиться к каждому объекту, передав туда кастомные аргументы
Однако, процесс можно усовершенствовать в помощью конструктора (на самом деле инициализатора, но мы в этой статье не будем углубляться в разницу). Конструктор вызывается автоматически при создании экземпляра.
Для этого служит метод __init__().
Перепишем наш класс и убедимся, что его работа не изменилась:
Важно:
- метод __init__(), как и другие методы класса должен принимать как минимум 1 аргумент self
- к аргументам объекта можно обращаться из метода как аргументам self (например, self.arg)
- Если аргумент создаётся конструктором __init__, то его не нужно описывать в классе как отдельную переменную
Если для конструктора __init__ мы зададим какие-то аргументы кроме self, то их можно будет передать в конструктор при создании экземпляра объекта, и сразу записать в аргументы, если необходимо.
Давайте создадим чуть более осмысленный класс.
Пусть это будет класс «Точка». Точка у нас будет характеризоваться 2 координатами (x, y).
И сразу зададим метод для нашей точки, вычисляющий расстояние от неё до другой точки (для этого воспользуемся теоремой Пифагора):
Здесь метод dist принимает 2 аргумента: экземпляр текущего объекта и ещё одного, между которыми необходимо найти расстояние.
Поскольку метод применяется к текущему экземпляру, то при вызове метода в скобках я указываю только 2ю точку).
Если я хочу передавать в мой метод аргументы привычным образом (как аргументы в скобках по порядку), то мне необходимо указать полный путь до метода. Он начнётся с имени класса:
Обратите внимание, что 2й способ обращения позволяет использовать классы как хранилище функций даже для стандартных типов данных.
Вот пример такого «хранилища»:
Заметим, что если мы попытаемся напечатать экземпляр объекта (а не его атрибуты, как раньше), то ничего хорошего не получим:
Мы можем понять экземпляром какого класса объект является и на какую область памяти смотрит указатель, но в работе это довольно бесполезно.
Согласитесь, печатая экземпляр списка мы получаем список — это удобно.
Воспользуемся стандартным методом __str__, который вызывается при его печати с помощью print:
Интересный эффект, который можно заметить — после пересоздания класса ранее созданные объекты не меняют своего поведения.
Дело в том, что класс — это тоже объект.
С точки зрения python мы создали 2 объекта. И на базе 1-ого создали несколько экземпляров.
Поэтому чтобы новые методы добавились у объектов, объекты придётся пересоздать.
Давайте заведём ещё 1 экземпляр объекта с точно такими же координатами, что и первый.
В бытовом понимании 2 такие точки «равны». Но что будет, если мы их сравним?
С точки зрения python это 2 разных объекта, а потому они НЕ равны.
Чтобы это исправить можно написать стандартный метод __eq__:
Замечу, что если мы заведём по новому атрибуту у наших точек (например, цвету), то операция сравнения их учитывать не будет:
Геттеры и Сеттеры
Идея геттеров и сеттеров заключается в том, что передавать в экземпляр класса значения атрибутов явно — довольно опасная идея.Т.к. питон язык с динамический типизацией, то мы можем передать любой тип данных в переменную с одним и тем же именем внутри разных экземпляров (мы так и делали раньше и считали это даже преимуществом)
Но иногда при добавлении атрибута имеет смысл провести валидацию. Или иметь метод который не перезатирает значение, а добавляет (примером такого метода является append для списков).
Добавим в наш класс 2 новых метода:
- сеттер — setColor — проверяет, что передаётся строка и записывает её в атрибут color экземпляра. Если передан другой тип данных, возвращает ошибку.
- геттер — getColor — возвращает значение атрибута color текущего экземпляра
По идее на этом этапе надо переписать все методы нашего класса, чтобы в них использовались геттеры и сеттеры вместо прямых обращений к атрибутам.
=)
Наследование
Идея в том, чтобы хранить в классе только необходимые для него объекты и атрибуты.И структурировать, объединить в иерархию объекты.
Обычно это иллюстрируется на примерах животных: кошечки, собачки, кролики и т.п.
Есть класс животные, он имеет
- атрибуты: число ног, имя, возраст.
- методы: геттеры и сеттеры
Теперь создадим класс кошки. Кошки — тоже животные. Поэтому все атрибуты и методы класса животные им тоже присущи. Но кроме этого, у них могут быть свои:
- атрибуты: имя и т.п.
- методы: «говорение» (мяу) и т.п.
Чтобы не дублировать код, класс кошки наследуется от класса животные.
Наследник получает все методы и атрибуты родителя, а так же может некоторые из них переопределить (например, если мы сделаем класс «птицы» наследником класса «животные», то, вероятно, ограничение на число ног изменится с 4 до 2), а так же задать собственные атрибуты и методы.
Давайте в нашем примере представим, что наш класс точек — это объекты на географической карте. Точка может использоваться для оформления (например, прокладки маршрута из точек).
А новый класс будет представлять из себя географический маркер: банкомат, достопримечательность, организацию или что-то иное.
Новый класс будет наследником обычной точки, но мы чуть расширим конструктор, чтобы иметь больше атрибутов:
Как видим, наш класс получил возможность использовать сеттер родительского класса, да и стандартная функция __str__ тоже наследуется.
Давайте зададим нашему классу новый метод __str__, чтобы при выводе на печать понимать что это не просто точка, именно маркер. И внутри будем использовать метод __str__ родительского класса:
Т.е. вы всегда можете обратиться к родительским методам у экземпляров дочерних классов, если это необходимо.
Давайте создадим ещё пару классов.
1 будет идентичен предыдущим — это будет класс иконок с геттером и сеттером:
Такие классы ещё иногда называются «примесью», дальше станет понятно почему.
А вот 2 будет интереснее. Это будет класс организации. И мы не станем записывать для него ни атрибутов, ни классов. Но унаследуем его от 2 родителей:
Удивительно, но это работает.
При этом:
- наследник получает все методы и атрибуты обоих родителей.
- если у нескольких родителей есть одноимённые методы, то автоматически наследник получит методы того, кто раньше в списке (в нашем случае раньше был гео маркер, поэтому конструктор был унаследован от него, а не от организации).
Наследование от нескольких родителей иногда считается сомнительной практикой, будьте с ним аккуратны.
Переменные класса
Мы уже говорили про атрибуты в качестве хранилища данных (мы даже создавали их внутри класса в самом начале).Есть ещё одно интересное применение для них — переменная класса. Т.е переменные, которые хранятся в классе, а не в экземпляре.
Модифицируем конструктор организации (добавим заодно поддержку url). В классе создадим переменную tag с первоначальным значением равным 0. В конструкторе же запишем в переменную ID создаваемого экземпляра значение из tag, а tag после этого увеличим на 1:
Таким образом мы получили:
- в атрибуте ID каждого объекта хранится его уникальный порядковый номер
- в переменной tag класса хранится число созданных объектов (тут надо быть осторожнее, так как возможно мы захотим уменьшать это число при удалении объекта).
Ну и не забываем, что каждый экземпляр имеет доступ к атрибутам класса помимо собственных, т.е. tag:
Переиспользование методов
Мы уже говорили про наследование методов, мы даже использовали методы родительского класса.Но можно наследовать часть родительского метода (и собирать из нескольких родительских 1 свой). Сократим наш код организации, унаследовав конструкторы гео маркера и иконки:
Мы совместили 2 наследуемых метода и свой код.
И всё это работает.
=)
Полезные ссылки:
Python | Классы и объекты
Классы и объекты
Последнее обновление: 06.07.2018
Python поддерживает объектно-ориентированную парадигму программирования, а это значит, что мы можем определить компоненты программы в виде классов.
Класс является шаблоном или формальным описанием объекта, а объект представляет экземпляр этого класса, его реальное воплощение. Можно провести следующую аналогию: у всех у нас есть некоторое представление о человеке — наличие двух рук, двух ног, головы, пищеварительной, нервной системы, головного мозга и т.д. Есть некоторый шаблон — этот шаблон можно назвать классом. Реально же существующий человек (фактически экземпляр данного класса) является объектом этого класса.
С точки зрения кода класс объединяет набор функций и переменных, которые выполняют определенную задачу. Функции класса еще называют методами. Они определяют поведение класса. А переменные класса называют атрибутами- они хранят состояние класса
Класс определяется с помощью ключевого слова class:
class название_класса: методы_класса
Для создания объекта класса используется следующий синтаксис:
название_объекта = название_класса([параметры])
Например, определим простейший класс Person, который будет представлять человека:
class Person: name = "Tom" def display_info(self): print("Привет, меня зовут", self.name) person1 = Person() person1.display_info() # Привет, меня зовут Tom person2 = Person() person2.name = "Sam" person2.display_info() # Привет, меня зовут Sam
Класс Person определяет атрибут name, который хранит имя человека, и метод display_info, с помощью которого выводится информация о человеке.
При определении методов любого класса следует учитывать, что все они должны принимать в качестве первого параметра ссылку на текущий объект, который согласно условностям называется
self (в ряде языков программирования есть своего рода аналог — ключевое слово this). Через эту ссылку внутри класса мы можем обратиться к методам или атрибутам этого же класса.
В частности, через выражение self.name
можно получить имя пользователя.
После определения класс Person создаем пару его объектов — person1 и person2. Используя имя объекта, мы можем обратиться к его методам и атрибутам.
В данном случае у каждого из объектов вызываем метод display_info()
, который выводит строку на консоль, и у второго объекта также изменяем атрибут name.
При этом при вызове метода display_info не надо передавать значение для параметра self.
Конструкторы
Для создания объекта класса используется конструктор. Так, выше когда мы создавали объекты класса Person, мы использовали конструктор по умолчанию, который неявно имеют все классы:
person1 = Person() person2 = Person()
Однако мы можем явным образом определить в классах конструктор с помощью специального метода, который называется __init(). К примеру, изменим класс Person, добавив в него конструктор:
class Person: # конструктор def __init__(self, name): self.name = name # устанавливаем имя def display_info(self): print("Привет, меня зовут", self.name) person1 = Person("Tom") person1.display_info() # Привет, меня зовут Tom person2 = Person("Sam") person2.display_info() # Привет, меня зовут Sam
В качестве первого параметра конструктор также принимает ссылку на текущий объект — self. Нередко в конструкторах устанавливаются атрибуты класса.
Так, в данном случае в качестве второго параметра в конструктор передается имя пользователя, которое устанавливается для атрибута self.name
.
Причем для атрибута необязательно определять в классе переменную name, как это было в предыдущей версии класса Person. Установка значения
self.name = name
уже неявно создает атрибут name.
person1 = Person("Tom") person2 = Person("Sam")
В итоге мы получим следующий консольный вывод:
Привет, меня зовут Tom Привет, меня зовут Sam
Деструктор
После окончания работы с объектом мы можем использовать оператор del для удаления его из памяти:
person1 = Person("Tom") del person1 # удаление из памяти # person1.display_info() # Этот метод работать не будет, так как person1 уже удален из памяти
Стоит отметить, что в принципе это необязательно делать, так как после окончания работы скрипта все объекты автоматически удаляются из памяти.
Кроме того, мы можем определить определить в классе деструктор, реализовав встроенную функцию __del__, который будет вызываться либо в результате вызова оператора del, либо при автоматическом удалении объекта. Например:
class Person: # конструктор def __init__(self, name): self.name = name # устанавливаем имя def __del__(self): print(self.name,"удален из памяти") def display_info(self): print("Привет, меня зовут", self.name) person1 = Person("Tom") person1.display_info() # Привет, меня зовут Tom del person1 # удаление из памяти person2 = Person("Sam") person2.display_info() # Привет, меня зовут Sam
Консольный вывод:
Привет, меня зовут Tom Tom удален из памяти Привет, меня зовут Sam Sam удален из памяти
Определение классов в модулях и подключение
Как правило, классы размещаются в отдельных модулях и затем уже импортируются в основой скрипт программы. Пусть у нас будет в проекте два файла: файл main.py (основной скрипт программы) и classes.py (скрипт с определением классов).
В файле classes.py определим два класса:
class Person: # конструктор def __init__(self, name): self.name = name # устанавливаем имя def display_info(self): print("Привет, меня зовут", self.name) class Auto: def __init__(self, name): self.name = name def move(self, speed): print(self.name, "едет со скоростью", speed, "км/ч")
В дополнение к классу Person здесь также определен класс Auto, который представляет машину и который имеет метод move и атрибут name. Подключим эти классы и используем их в скрипте main.py:
from classes import Person, Auto tom = Person("Tom") tom.display_info() bmw = Auto("BMW") bmw.move(65)
Подключение классов происходит точно также, как и функций из модуля. Мы можем подключить весь модуль выражением:
import classes
Либо подключить отдельные классы, как в примере выше.
В итоге мы получим следующий консольный вывод:
Привет, меня зовут Tom BMW едет со скоростью 65 км/ч
Python. Урок 14. Классы и объекты
Данный урок посвящен объектно-ориентированному программированию в Python. Разобраны такие темы как создание объектов и классов, работа с конструктором, наследование и полиморфизм в Python.
Объектно-ориентированное программирование (ООП) является методологией разработки программного обеспечения, в основе которой лежит понятие класса и объекта, при этом сама программа создается как некоторая совокупность объектов, которые взаимодействую друг с другом и с внешним миром. Каждый объект является экземпляром некоторого класса. Классы образуют иерархии. Более подробно о понятии ООП можно прочитать на википедии.
Выделяют три основных “столпа” ООП- это инкапсуляция, наследование и полиморфизм.
ИнкапсуляцияПод инкапсуляцией понимается сокрытие деталей реализации, данных и т.п. от внешней стороны. Например, можно определить класс “холодильник”, который будет содержать следующие данные: производитель, объем, количество камер хранения, потребляемая мощность и т.п., и методы: открыть/закрыть холодильник, включить/выключить, но при этом реализация того, как происходит непосредственно включение и выключение пользователю вашего класса не доступна, что позволяет ее менять без опасения, что это может отразиться на использующей класс «холодильник» программе. При этом класс становится новым типом данных в рамках разрабатываемой программы. Можно создавать переменные этого нового типа, такие переменные называются объекты.
НаследованиеПод наследованием понимается возможность создания нового класса на базе существующего. Наследование предполагает наличие отношения “является” между классом наследником и классом родителем. При этом класс потомок будет содержать те же атрибуты и методы, что и базовый класс, но при этом его можно (и нужно) расширять через добавление новых методов и атрибутов.
Примером базового класса, демонстрирующего наследование, можно определить класс “автомобиль”, имеющий атрибуты: масса, мощность двигателя, объем топливного бака и методы: завести и заглушить. У такого класса может быть потомок – “грузовой автомобиль”, он будет содержать те же атрибуты и методы, что и класс “автомобиль”, и дополнительные свойства: количество осей, мощность компрессора и т.п..
ПолиморфизмПолиморфизм позволяет одинаково обращаться с объектами, имеющими однотипный интерфейс, независимо от внутренней реализации объекта. Например, с объектом класса “грузовой автомобиль” можно производить те же операции, что и с объектом класса “автомобиль”, т.к. первый является наследником второго, при этом обратное утверждение неверно (во всяком случае не всегда). Другими словами полиморфизм предполагает разную реализацию методов с одинаковыми именами. Это очень полезно при наследовании, когда в классе наследнике можно переопределить методы класса родителя.
Создание классов и объектовСоздание класса в Python начинается с инструкции class. Вот так будет выглядеть минимальный класс.
class C: pass
Класс состоит из объявления (инструкция class), имени класса (нашем случае это имя C) и тела класса, которое содержит атрибуты и методы (в нашем минимальном классе есть только одна инструкция pass).
Для того чтобы создать объект класса необходимо воспользоваться следующим синтаксисом:
имя_объекта = имя_класса()
Статические и динамические атрибуты классаКак уже было сказано выше, класс может содержать атрибуты и методы. Атрибут может быть статическим и динамическим (уровня объекта класса). Суть в том, что для работы со статическим атрибутом, вам не нужно создавать экземпляр класса, а для работы с динамическим – нужно. Пример:
class Rectangle: default_color = "green" def __init__(self, width, height): self.width = width self.height = height
В представленном выше классе, атрибут default_color – это статический атрибут, и доступ к нему, как было сказано выше, можно получить не создавая объект класса Rectangle.
>>> Rectangle.default_color 'green'
width и height – это динамические атрибуты, при их создании было использовано ключевое слово self. Пока просто примите это как должное, более подробно про self будет рассказано ниже. Для доступа к width и height предварительно нужно создать объект класса Rectangle:
>>> rect = Rectangle(10, 20) >>> rect.width 10 >>> rect.height 20
Если обратиться через класс, то получим ошибку:
>>> Rectangle.width Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'Rectangle' has no attribute 'width'
При этом, если вы обратитесь к статическому атрибуту через экземпляр класса, то все будет ОК, до тех пор, пока вы не попытаетесь его поменять.
Проверим ещё раз значение атрибута default_color:
>>> Rectangle.default_color 'green'
Присвоим ему новое значение:
>>> Rectangle.default_color = "red" >>> Rectangle.default_color 'red'
Создадим два объекта класса Rectangle и проверим, что default_color у них совпадает:
>>> r1 = Rectangle(1,2) >>> r2 = Rectangle(10, 20) >>> r1.default_color 'red' >>> r2.default_color 'red'
Если поменять значение default_color через имя класса Rectangle, то все будет ожидаемо: у объектов r1 и r2 это значение изменится, но если поменять его через экземпляр класса, то у экземпляра будет создан атрибут с таким же именем как статический, а доступ к последнему будет потерян:
Меняем default_color через r1:
>>> r1.default_color = "blue" >>> r1.default_color 'blue'
При этом у r2 остается значение статического атрибута:
>>> r2.default_color 'red' >>> Rectangle.default_color 'red'
Вообще напрямую работать с атрибутами – не очень хорошая идея, лучше для этого использовать свойства.
Методы классаДобавим к нашему классу метод. Метод – это функция, находящаяся внутри класса и выполняющая определенную работу.
Методы бывают статическими, классовыми (среднее между статическими и обычными) и уровня класса (будем их называть просто словом метод). Статический метод создается с декоратором @staticmethod, классовый – с декоратором @classmethod, первым аргументом в него передается cls, обычный метод создается без специального декоратора, ему первым аргументом передается self:
class MyClass: @staticmethod def ex_static_method(): print("static method") @classmethod def ex_class_method(cls): print("class method") def ex_method(self): print("method")
Статический и классовый метод можно вызвать, не создавая экземпляр класса, для вызова ex_method() нужен объект:
>>> MyClass.ex_static_method() static method >>> MyClass.ex_class_method() class method >>> MyClass.ex_method() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ex_method() missing 1 required positional argument: 'self' >>> m = MyClass() >>> m.ex_method() methodКонструктор класса и инициализация экземпляра класса
В Python разделяют конструктор класса и метод для инициализации экземпляра класса. Конструктор класса это метод __new__(cls, *args, **kwargs) для инициализации экземпляра класса используется метод __init__(self). При этом, как вы могли заметить __new__ – это классовый метод, а __init__ таким не является. Метод __new__ редко переопределяется, чаще используется реализация от базового класса object (см. раздел Наследование), __init__ же наоборот является очень удобным способом задать параметры объекта при его создании.
Создадим реализацию класса Rectangle с измененным конструктором и инициализатором, через который задается ширина и высота прямоугольника:
class Rectangle: def __new__(cls, *args, **kwargs): print("Hello from __new__") return super().__new__(cls) def __init__(self, width, height): print("Hello from __init__") self.width = width self.height = height >>> rect = Rectangle(10, 20) Hello from __new__ Hello from __init__ >>> rect.width 10 >>> rect.height 20Что такое self?
До этого момента вы уже успели познакомиться с ключевым словом self. self – это ссылка на текущий экземпляр класса, в таких языках как Java, C# аналогом является ключевое слово this. Через self вы получаете доступ к атрибутам и методам класса внутри него:
class Rectangle: def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height
В приведенной реализации метод area получает доступ к атрибутам width и height для расчета площади. Если бы в качестве первого параметра не было указано self, то при попытке вызвать area программа была бы остановлена с ошибкой.
Уровни доступа атрибута и методаЕсли вы знакомы с языками программирования Java, C#, C++ то, наверное, уже задались вопросом: “а как управлять уровнем доступа?”. В перечисленных языка вы можете явно указать для переменной, что доступ к ней снаружи класса запрещен, это делается с помощью ключевых слов (private, protected и т.д.). В Python таких возможностей нет, и любой может обратиться к атрибутам и методам вашего класса, если возникнет такая необходимость. Это существенный недостаток этого языка, т.к. нарушается один из ключевых принципов ООП – инкапсуляция. Хорошим тоном считается, что для чтения/изменения какого-то атрибута должны использоваться специальные методы, которые называются getter/setter, их можно реализовать, но ничего не помешает изменить атрибут напрямую. При этом есть соглашение, что метод или атрибут, который начинается с нижнего подчеркивания, является скрытым, и снаружи класса трогать его не нужно (хотя сделать это можно).
Внесем соответствующие изменения в класс Rectangle:
class Rectangle: def __init__(self, width, height): self._width = width self._height = height def get_width(self): return self._width def set_width(self, w): self._width = w def get_height(self): return self._height def set_height(self, h): self._height = h def area(self): return self._width * self._height
В приведенном примере для доступа к _width и _height используются специальные методы, но ничего не мешает вам обратиться к ним (атрибутам) напрямую.
>>> rect = Rectangle(10, 20) >>> rect.get_width() 10 >>> rect._width 10
Если же атрибут или метод начинается с двух подчеркиваний, то тут напрямую вы к нему уже не обратитесь (простым образом). Модифицируем наш класс Rectangle:
class Rectangle: def __init__(self, width, height): self.__width = width self.__height = height def get_width(self): return self.__width def set_width(self, w): self.__width = w def get_height(self): return self.__height def set_height(self, h): self.__height = h def area(self): return self.__width * self.__height
Попытка обратиться к __width напрямую вызовет ошибку, нужно работать только через get_width():
>>> rect = Rectangle(10, 20) >>> rect.__width Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Rectangle' object has no attribute '__width' >>> rect.get_width() 10
Но на самом деле это сделать можно, просто этот атрибут теперь для внешнего использования носит название: _Rectangle__width:
>>> rect._Rectangle__width 10 >>> rect._Rectangle__width = 20 >>> rect.get_width() 20Свойства
Свойством называется такой метод класса, работа с которым подобна работе с атрибутом. Для объявления метода свойством необходимо использовать декоратор @property.
Важным преимуществом работы через свойства является то, что вы можете осуществлять проверку входных значений, перед тем как присвоить их атрибутам.
Сделаем реализацию класса Rectangle с использованием свойств:
class Rectangle: def __init__(self, width, height): self.__width = width self.__height = height @property def width(self): return self.__width @width.setter def width(self, w): if w > 0: self.__width = w else: raise ValueError @property def height(self): return self.__height @height.setter def height(self, h): if h > 0: self.__height = h else: raise ValueError def area(self): return self.__width * self.__height
Теперь работать с width и height можно так, как будто они являются атрибутами:
>>> rect = Rectangle(10, 20) >>> rect.width 10 >>> rect.height 20
Можно не только читать, но и задавать новые значения свойствам:
>>> rect.width = 50 >>> rect.width 50 >>> rect.height = 70 >>> rect.height 70
Если вы обратили внимание: в setter’ах этих свойств осуществляется проверка входных значений, если значение меньше нуля, то будет выброшено исключение ValueError:
>>> rect.width = -10 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "test.py", line 28, in width raise ValueError ValueErrorНаследование
В организации наследования участвуют как минимум два класса: класс родитель и класс потомок. При этом возможно множественное наследование, в этом случае у класса потомка может быть несколько родителей. Не все языки программирования поддерживают множественное наследование, но в Python можно его использовать. По умолчанию все классы в Python являются наследниками от object, явно этот факт указывать не нужно.
Синтаксически создание класса с указанием его родителя выглядит так:
class имя_класса(имя_родителя1, [имя_родителя2,…, имя_родителя_n])
Переработаем наш пример так, чтобы в нем присутствовало наследование:
class Figure: def __init__(self, color): self.__color = color @property def color(self): return self.__color @color.setter def color(self, c): self.__color = c class Rectangle(Figure): def __init__(self, width, height, color): super().__init__(color) self.__width = width self.__height = height @property def width(self): return self.__width @width.setter def width(self, w): if w > 0: self.__width = w else: raise ValueError @property def height(self): return self.__height @height.setter def height(self, h): if h > 0: self.__height = h else: raise ValueError def area(self): return self.__width * self.__height
Родительским классом является Figure, который при инициализации принимает цвет фигуры и предоставляет его через свойства. Rectangle – класс наследник от Figure. Обратите внимание на его метод __init__: в нем первым делом вызывается конструктор (хотя это не совсем верно, но будем говорить так) его родительского класса:
super().__init__(color)
super – это ключевое слово, которое используется для обращения к родительскому классу.
Теперь у объекта класса Rectangle помимо уже знакомых свойств width и height появилось свойство color:
>>> rect = Rectangle(10, 20, "green") >>> rect.width 10 >>> rect.height 20 >>> rect.color 'green' >>> rect.color = "red" >>> rect.color 'red'Полиморфизм
Как уже было сказано во введении в рамках ООП полиморфизм, как правило, используется с позиции переопределения методов базового класса в классе наследнике. Проще всего это рассмотреть на примере. Добавим в наш базовый класс метод info(), который печатает сводную информацию по объекту класса Figure и переопределим этот метод в классе Rectangle, добавим в него дополнительные данные:
class Figure: def __init__(self, color): self.__color = color @property def color(self): return self.__color @color.setter def color(self, c): self.__color = c def info(self): print("Figure") print("Color: " + self.__color) class Rectangle(Figure): def __init__(self, width, height, color): super().__init__(color) self.__width = width self.__height = height @property def width(self): return self.__width @width.setter def width(self, w): if w > 0: self.__width = w else: raise ValueError @property def height(self): return self.__height @height.setter def height(self, h): if h > 0: self.__height = h else: raise ValueError def info(self): print("Rectangle") print("Color: " + self.color) print("Width: " + str(self.width)) print("Height: " + str(self.height)) print("Area: " + str(self.area())) def area(self): return self.__width * self.__height
Посмотрим, как это работает
>>> fig = Figure("orange") >>> fig.info() Figure Color: orange >>> rect = Rectangle(10, 20, "green") >>> rect.info() Rectangle Color: green Width: 10 Height: 20 Area: 200
Таким образом, класс наследник может расширять функционал класса родителя.
P.S.Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.
<<< Python. Урок 13. Модули и пакеты Python. Урок 15. Итераторы и генераторы>>>
Python 3 Объектно-ориентированное программирование — третье издание
Давайте свяжем все наши новые объектно-ориентированные знания вместе, пройдя несколько итераций объектно-ориентированного проектирования на довольно реальном примере. Система, которую мы будем моделировать, представляет собой библиотечный каталог. Библиотеки отслеживали свои запасы на протяжении веков, первоначально используя карточные каталоги, а в последнее время — электронные реестры. В современных библиотеках есть веб-каталоги, которые мы можем запрашивать у себя дома.
Начнем с анализа.Местный библиотекарь попросил нас написать новую программу-каталог карточек, потому что их старая программа на базе Windows XP уродлива и устарела. Это не дает нам подробностей, но прежде чем мы начнем запрашивать дополнительную информацию, давайте рассмотрим, что мы уже знаем о каталогах библиотек.
Каталоги содержат списки книг. Люди ищут их, чтобы найти книги по определенным предметам, с определенными названиями или определенного автора. Книги можно однозначно идентифицировать по международному стандартному книжному номеру ( ISBN ).Каждая книга имеет номер в десятичной системе Дьюи ( DDS ), который помогает найти ее на определенной полке.
Этот простой анализ показывает нам некоторые очевидные объекты в системе. Мы быстро определяем Книга как наиболее важный объект с уже упомянутыми несколькими атрибутами, такими как автор, название, тема, ISBN и номер DDS, а также каталог как своего рода менеджер для книг.
Мы также замечаем несколько других объектов, которые могут или не могут нуждаться в моделировании в системе.Для целей каталогизации все, что нам нужно для поиска книги по автору, — это атрибут author_name в книге. Однако авторы также являются объектами, и мы можем захотеть сохранить некоторые другие данные об авторе. Размышляя над этим, мы можем вспомнить, что у некоторых книг несколько авторов. Внезапно идея иметь один атрибут author_name для объектов кажется немного глупой. Список авторов, связанных с каждой книгой, явно лучше.
Связь между автором и книгой явно связана с ассоциацией, поскольку вы никогда не скажете , что книга является автором (это не наследование), и утверждение , что у книги есть автор , хотя грамматически правильное, не означает, что авторы являются частью книг (это не агрегация).Действительно, любой автор может быть связан с несколькими книгами.
Мы также должны обратить внимание на существительное (существительные всегда являются хорошими кандидатами для объектов) полка . Полка — это объект, который нужно смоделировать в системе каталогизации? Как мы идентифицируем индивидуальную полку? Что произойдет, если книга будет сохранена в конце одной полки, а затем перемещена в начало следующей полки, потому что новая книга была вставлена на предыдущую полку?
DDS был разработан, чтобы помочь найти физические книги в библиотеке.Таким образом, хранения атрибута DDS вместе с книгой должно быть достаточно, чтобы найти его, независимо от того, на какой полке он хранится. Таким образом, мы можем, по крайней мере, на время удалить полку из нашего списка конкурирующих объектов.
Другой сомнительный объект в системе — это пользователь. Нужно ли нам что-нибудь знать о конкретном пользователе, например, его имя, адрес или список просроченных книг? Пока что библиотекарь сказал нам только, что им нужен каталог; они ничего не сказали об отслеживании подписок или просроченных уведомлений.В глубине души мы также отмечаем, что авторы и пользователи — это разные люди; здесь в будущем могут появиться полезные отношения наследования.
В целях каталогизации мы решили, что нам пока не нужно идентифицировать пользователя. Мы можем предположить, что пользователь будет искать в каталоге, но нам не нужно активно моделировать их в системе, кроме предоставления интерфейса, который позволяет им выполнять поиск.
Мы определили несколько атрибутов в книге, но какими свойствами обладает каталог? Есть ли у какой-либо библиотеки более одного каталога? Нужно ли их однозначно идентифицировать? Очевидно, что каталог каким-то образом должен содержать коллекцию книг, но этот список, вероятно, не является частью общедоступного интерфейса.
А как насчет поведения? В каталоге явно нужен метод поиска, возможно, отдельные по авторам, названиям и тематикам. Есть ли какое-нибудь поведение в книгах? Нужен ли метод предварительного просмотра? Или предварительный просмотр можно определить по атрибуту первой страницы, а не по методу?
Вопросы в предыдущем обсуждении являются частью фазы объектно-ориентированного анализа. Но в сочетании с вопросами мы уже определили несколько ключевых объектов, которые являются частью дизайна. Действительно, то, что вы только что видели, — это несколько микролитров между анализом и дизайном.
Скорее всего, все эти итерации произойдут при первой встрече с библиотекарем. Однако перед этой встречей мы уже можем набросать самый базовый дизайн для объектов, которые мы конкретно идентифицировали, а именно:
Вооружившись этой базовой схемой и карандашом для интерактивного улучшения, мы встречаемся с библиотекарем. Они говорят нам, что это хорошее начало, но библиотеки обслуживают не только книги; у них также есть DVD, журналы и компакт-диски, ни один из которых не имеет номера ISBN или DDS.Однако все эти типы элементов можно однозначно идентифицировать по номеру UPC. Напоминаем библиотекарю, что они должны найти предметы на полке, и эти предметы, вероятно, не организованы СКП. Библиотекарь объясняет, что каждый тип организован по-своему. Компакт-диски — это в основном аудиокниги, а их в наличии всего два десятка, поэтому они организованы по фамилии автора. DVD делятся по жанрам и далее упорядочены по названиям. Журналы сгруппированы по заголовкам, а затем уточняются по томам и номерам выпусков.Книги, как мы уже догадались, организованы по номеру DDS.
Не имея предыдущего опыта объектно-ориентированного проектирования, мы могли бы рассмотреть возможность добавления отдельных списков DVD-дисков, компакт-дисков, журналов и книг в наш каталог и выполнять поиск по каждому из них по очереди. Проблема в том, что, за исключением некоторых расширенных атрибутов и определения физического местоположения элемента, все эти элементы ведут себя примерно одинаково. Это работа по наследству! Мы быстро обновляем нашу диаграмму UML следующим образом:
Библиотекарь понимает суть нарисованной нами схемы, но его немного смущает функция locate .Мы объясняем это на конкретном примере использования, когда пользователь ищет слово bunnies . Пользователь сначала отправляет поисковый запрос в каталог. Каталог запрашивает свой внутренний список предметов и находит книгу и DVD с кроликами в названии. На этом этапе каталогу все равно, содержит ли он DVD, книгу, компакт-диск или журнал; что касается каталога, все позиции идентичны. Однако пользователь хочет знать, как найти физические предметы, поэтому каталог будет упущен, если он просто вернет список названий.Таким образом, он вызывает метод locate для двух обнаруженных элементов. Метод locate книги возвращает номер DDS, который можно использовать для поиска полки, на которой находится книга. DVD определяется путем возврата жанра и названия DVD. Затем пользователь может посетить раздел DVD, найти раздел, содержащий этот жанр, и найти конкретный DVD, отсортированный по заголовкам.
Как мы объясняем, мы набросаем схему последовательности операций UML , объясняющую, как взаимодействуют различные объекты:
В то время как диаграммы классов описывают отношения между классами, диаграммы последовательностей описывают определенные последовательности сообщений, передаваемых между объектами.Пунктирная линия, свисающая с каждого объекта, — это линия жизни , описывающая время жизни объекта. Более широкие прямоугольники на каждой линии жизни представляют активную обработку в этом объекте (где нет прямоугольника, объект в основном сидит без дела, ожидая, что что-то произойдет). Горизонтальные стрелки между линиями жизни указывают на конкретные сообщения. Сплошные стрелки представляют вызываемые методы, а пунктирные стрелки со сплошными головками представляют значения, возвращаемые методом.
Половинки стрелок указывают на асинхронные сообщения, отправленные объекту или от него.Асинхронное сообщение обычно означает, что первый объект вызывает метод второго объекта, который немедленно возвращается. После некоторой обработки второй объект вызывает метод первого объекта, чтобы присвоить ему значение. Это отличается от обычных вызовов методов, которые выполняют обработку в методе и немедленно возвращают значение.
Диаграммы последовательностей, как и все диаграммы UML, лучше всего использовать только тогда, когда они необходимы. Нет смысла рисовать диаграмму UML для рисования диаграммы.Однако, когда вам нужно сообщить о серии взаимодействий между двумя объектами, диаграмма последовательности является очень полезным инструментом.
К сожалению, наша диаграмма классов до сих пор выглядит запутанной. Мы замечаем, что актеры на DVD и артисты на компакт-дисках — это разные люди, но к ним относятся иначе, чем к авторам книг. Библиотекарь также напоминает нам, что большинство их компакт-дисков — это аудиокниги, у которых есть авторы, а не художники.
Как мы можем работать с разными людьми, которые вносят свой вклад в создание названия? Одна очевидная реализация — создать класс Person с именем человека и другими соответствующими деталями, а затем создать его подклассы для художников, авторов и актеров.Однако действительно ли здесь необходимо наследование? В целях поиска и каталогизации нам все равно, что актерское мастерство и писательство — это два совершенно разных вида деятельности. Если бы мы проводили экономическое моделирование, было бы разумно выделить отдельные классы актеров и авторов и разные методы calculate_income, и perform_job , но для целей каталогизации достаточно знать, какой вклад внес человек в элемент. Поразмыслив над этим, мы понимаем, что все элементы имеют один или несколько объектов Contributor , поэтому мы перемещаем отношение автора из книги в ее родительский класс:
Множественность отношения Contributor / LibraryItem составляет многие ко многим , на что указывает символ * на обоих концах одной связи.Любой элемент библиотеки может иметь более одного участника (например, несколько актеров и режиссер на DVD). Многие авторы пишут много книг, поэтому их можно прикрепить к нескольким объектам библиотеки.
Это небольшое изменение, хотя и выглядит немного чище и проще, но лишено важной информации. Мы все еще можем сказать, кто внес свой вклад в конкретный элемент библиотеки, но мы не знаем, как они внесли свой вклад. Они были режиссером или актером? Они написали аудиокнигу или были голосом, который рассказывал книгу?
Было бы неплохо, если бы мы могли просто добавить атрибут Contributor_type в класс Contributor , но это развалится, когда мы имеем дело с людьми с разносторонними талантами, которые одновременно являются авторами книг и режиссерами фильмов.
Один из вариантов — добавить атрибуты к каждому из наших подклассов LibraryItem для хранения необходимой нам информации, например, Author в Book или Artist на CD , а затем установить связь со всеми этими свойствами укажите на класс Contributor . Проблема в том, что мы теряем много полиморфной элегантности. Если мы хотим перечислить участников элемента, мы должны искать определенные атрибуты этого элемента, такие как авторов или участников .Мы можем решить эту проблему, добавив метод GetContributors в класс LibraryItem , который подклассы могут переопределить. Тогда каталогу никогда не нужно знать, какие атрибуты запрашивают объекты; мы абстрагировали публичный интерфейс:
Просто глядя на эту диаграмму классов, кажется, что мы делаем что-то не так. Он громоздкий и хрупкий. Он может делать все, что нам нужно, но кажется, что его будет сложно поддерживать или расширять. Слишком много отношений, и слишком много классов будут затронуты модификациями любого одного класса.Похоже на спагетти и тефтели.
Теперь, когда мы изучили наследование как вариант и обнаружили, что оно желательно, мы можем вернуться к нашей предыдущей диаграмме на основе композиции, где Contributor был присоединен непосредственно к LibraryItem . Поразмыслив, мы можем увидеть, что на самом деле нам нужно только добавить еще одно отношение к совершенно новому классу, чтобы определить тип участника. Это важный шаг в объектно-ориентированном дизайне. Теперь мы добавляем класс к проекту, который предназначен для поддержки других объектов, вместо моделирования какой-либо части начальных требований.Мы реорганизуем дизайн, чтобы упростить объекты в системе, а не объекты в реальной жизни. Рефакторинг — важный процесс поддержки программы или дизайна. Целью рефакторинга является улучшение дизайна путем перемещения кода, удаления дублированного кода или сложных взаимосвязей в пользу более простых и элегантных дизайнов.
Этот новый класс состоит из Contributor и дополнительного атрибута, определяющего тип вклада человека в данный LibraryItem .Таких вкладов в конкретный LibraryItem может быть много, и один участник может одинаково вносить вклад в разные элементы. Следующая диаграмма очень хорошо передает эту конструкцию:
Сначала это отношение композиции выглядит менее естественным, чем отношения на основе наследования. Однако у него есть то преимущество, что мы можем добавлять новые типы вкладов без добавления нового класса в дизайн. Наследование наиболее полезно, когда подклассы имеют какую-то специализацию .Специализация — это создание или изменение атрибутов или поведения подкласса, чтобы он чем-то отличался от родительского класса. Кажется глупым создавать кучу пустых классов исключительно для идентификации различных типов объектов (такое отношение менее распространено среди Java и других программистов, все является объектом , но это распространено среди более прагматичных дизайнеров Python). Если мы посмотрим на версию наследования диаграммы, мы увидим группу подклассов, которые на самом деле ничего не делают:
Иногда важно понимать, когда не следует использовать объектно-ориентированные принципы.Этот пример того, когда не следует использовать наследование, является хорошим напоминанием о том, что объекты — это просто инструменты, а не правила.
OOP Python Tutorial: объектно-ориентированное программирование
Объектно-ориентированное программирование
Общее введение
Хотя Python является объектно-ориентированным языком без суеты и придирок, мы до сих пор намеренно избегали рассмотрения объектно-ориентированного программирования (ООП) в предыдущих главах нашего руководства по Python. Мы пропустили ООП, потому что убеждены, что легче и увлекательнее начать изучать Python, не зная всех деталей объектно-ориентированного программирования.
Несмотря на то, что мы избегали ООП, оно всегда присутствовало в упражнениях и примерах нашего курса. Мы использовали объекты и методы из классов, не объясняя должным образом их предысторию ООП. В этой главе мы поговорим о том, чего до сих пор не хватало. Мы предоставим введение в принципы объектно-ориентированного программирования в целом и в особенности ООП-подхода Python. ООП — один из самых мощных инструментов Python, но, тем не менее, вам не обязательно его использовать, т.е.е. вы также можете писать мощные и эффективные программы без него.
Хотя многие компьютерные ученые и программисты считают ООП современной парадигмой программирования, ее корни уходят в 1960-е годы. Первым языком программирования, использующим объекты, был Simula 67. Как следует из названия, Simula 67 была представлена в 1967 году. Важным прорывом в объектно-ориентированном программировании стал язык программирования Smalltalk в 1970-х.
Вы узнаете четыре основных принципа объектной ориентации и то, как Python работает с ними, в следующем разделе этого руководства по объектно-ориентированному программированию:
- Инкапсуляция
- Абстракция данных
- Полиморфизм
- Наследование
Прежде чем мы начнем раздел о том, как ООП используется в Python, мы хотим дать вам общее представление об объектно-ориентированном программировании.Для этого хотим обратить ваше внимание на публичную библиотеку. Давайте подумаем о таком огромном, как «Британская библиотека» в Лондоне или «Нью-Йоркская публичная библиотека» в Нью-Йорке. Если это поможет, вы можете представить себе библиотеки в Париже, Берлине, Оттаве или Торонто *. Каждый из них содержит организованную коллекцию книг, периодических изданий, газет, аудиокниг, фильмов и так далее.
Как правило, существует два противоположных способа хранения материала в библиотеке. Вы можете использовать метод «закрытого доступа», когда товар не отображается на открытых полках.В этой системе обученный персонал доставляет книги и другие публикации пользователям по запросу. Другой способ работы библиотеки — полки с открытым доступом, также известные как «открытые полки». «Открытый» означает открытый для всех пользователей библиотеки, а не только специально обученный персонал. В этом случае книги выставляются открыто. Императивные языки, такие как C, можно рассматривать как полочные библиотеки с открытым доступом. Пользователь может все. Пользователь должен найти книги и положить их обратно на нужную полку. Несмотря на то, что это хорошо для пользователя, в долгосрочной перспективе это может привести к серьезным проблемам.Например, некоторые книги будут потеряны, поэтому их будет сложно найти снова. Как вы уже догадались, «закрытый доступ» можно сравнить с объектно-ориентированным программированием. Аналогию можно увидеть так: книги и другие публикации, которые предлагает библиотека, подобны данным в объектно-ориентированной программе. Доступ к книгам ограничен, как и доступ к данным в ООП. Получить или вернуть книгу можно только через сотрудников. Штатные функции аналогичны методам в ООП, которые контролируют доступ к данным.Таким образом, данные — часто называемые атрибутами — в такой программе можно рассматривать как скрытые и защищенные оболочкой, и к ним могут получить доступ только специальные функции, обычно называемые методами в контексте ООП. Помещение данных в «оболочку» называется Encapsulation . Таким образом, библиотеку можно рассматривать как класс, а книгу — как экземпляр или объект этого класса. Вообще говоря, объект определяется классом. Класс — это формальное описание того, как спроектирован объект, то есть какие атрибуты и методы он имеет.Эти объекты также называются экземплярами. Выражения в большинстве случаев используются как синонимы. Не следует путать класс с объектом.
ООП на Python
Хотя мы не говорили о классах и объектной ориентации в предыдущих главах, мы работали с классами все время. Фактически, в Python все является классом. Гвидо ван Россум разработал язык по принципу «все первоклассно». Он писал: «Одной из моих целей в Python было сделать так, чтобы все объекты были« первоклассными ».«Под этим я имел в виду, что хотел, чтобы все объекты, которым можно было присвоить имя на языке (например, целые числа, строки, функции, классы, модули, методы и т. Д.), Имели одинаковый статус. То есть, они могли быть назначены переменные, помещенные в списки, сохраненные в словарях, переданные как аргументы и т. д. » (Блог, История Python, 27 февраля 2009 г.) Другими словами, «все» обрабатывается одинаково, все является классом: функции и методы являются значениями, такими же, как списки, целые числа или числа с плавающей запятой. Каждый из них является экземплярами своих соответствующих классов.
объектно-ориентированного программирования на Python | Набор 1 (класс, объект и члены)
Ниже представлена простая программа Python, которая создает класс с помощью одного метода.
Python
|
Вывод:
Hello
Как мы видим выше, мы создаем новый класс, используя оператор class и имя класса. За ним следует блок операторов с отступом, которые составляют тело класса. В этом случае мы определили единственный метод в классе.
Затем мы создаем объект / экземпляр этого класса, используя имя класса, за которым следует пара круглых скобок.
Объект:
Объект - это сущность, с которой связаны состояние и поведение.Это может быть любой объект реального мира, такой как мышь, клавиатура, стул, стол, ручка и т. Д. Целые числа, строки, числа с плавающей запятой, даже массивы и словари - все это объекты. Более конкретно, любое целое число или любая отдельная строка является объектом. Число 12 - это объект, строка «Hello, world» - это объект, список - это объект, который может содержать другие объекты, и так далее. Вы все время использовали предметы и, возможно, даже не осознавали этого.
Класс:
Класс - это проект, который определяет переменные и методы (характеристики), общие для всех объектов определенного типа.
Пример: Если Автомобиль является классом, то Audi A6 является объектом класса Автомобиль. Все автомобили обладают схожими характеристиками, такими как 4 колеса, 1 рулевое колесо, окна, тормоза и т. Д. Audi A6 (объект «Автомобиль») обладает всеми этими функциями.
Методы класса self
- должны иметь дополнительный первый параметр в определении метода. Мы не указываем значение для этого параметра при вызове метода, Python предоставляет его
- Если у нас есть метод, который не принимает аргументов, то у нас все равно должен быть один аргумент - self.См. Fun () в приведенном выше простом примере.
- Это похоже на этот указатель в C ++ и эту ссылку в Java.
Когда мы вызываем метод этого объекта как myobject.method (arg1, arg2), он автоматически преобразуется Python в MyClass.method (myobject, arg1, arg2) - это все, о чем идет речь в особом self.
Метод __init__
Метод __init__ аналогичен конструкторам в C ++ и Java. Он запускается, как только создается экземпляр объекта класса.Метод полезен для любой инициализации, которую вы хотите выполнить с вашим объектом.
Python
|
11 |
Мы также можем определять переменные экземпляра внутри обычных методов.
Python
адрес |
Вывод:
Noida, UP
Как создать пустой класс?
Мы можем создать пустой класс, используя инструкцию pass в Python.
Объектно-ориентированное программирование на Python | Набор 2 (Скрытие данных и печать объектов)
-xa0
Автор статьи Shwetanshu Rohatgi .Пожалуйста, напишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по теме, обсужденной выше
Внимание компьютерщик! Укрепите свои основы с помощью курса Python Programming Foundation и изучите основы.
Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS . И чтобы начать свое путешествие по машинному обучению, присоединяйтесь к Машинное обучение — курс базового уровня
PacktPublishing / Python-3-Object-Oriented-Programming-Third-Edition: Python 3 Object-Oriented Programming — Third Edition, опубликованный Пакет
Это репозиторий кода для объектно-ориентированного программирования Python 3 — третье издание, опубликованный Packt.
Создавайте надежное и удобное в обслуживании программное обеспечение с помощью объектно-ориентированных шаблонов проектирования на Python 3.8
О чем эта книга?
Объектно-ориентированное программирование (ООП) — это популярная парадигма проектирования, в которой данные и поведение инкапсулируются таким образом, что ими можно управлять вместе. Это третье издание Python 3 Object-Oriented Programming полностью объясняет классы, инкапсуляцию данных и исключения с акцентом на то, когда вы можете использовать каждый принцип для разработки хорошо спроектированного программного обеспечения.
В этой книге описаны следующие интересные особенности:
- Реализация объектов в Python путем создания классов и определения методов
- Распространенные методы параллелизма и подводные камни в Python 3
- Расширение функциональности класса с помощью наследования
- Поймите, когда использовать объектно-ориентированные функции и, что более важно, когда их не использовать
- Узнайте, что такое шаблоны проектирования и почему они отличаются в Python
- Откройте для себя простоту модульного тестирования и объясните, почему это так важно в Python
- Изучите объектно-ориентированное программирование одновременно с asyncio
Если вы чувствуете, что эта книга для вас, получите свой экземпляр сегодня же!
Инструкции и навигация
Весь код организован в папки.Например, Chapter02.
Код будет выглядеть следующим образом:
класс Point:
def __init __ (self, x = 0, y = 0):
self.move (х, у)
Для этой книги вам понадобится следующее: Если вы новичок в методах объектно-ориентированного программирования или у вас есть базовые навыки Python и вы хотите подробно изучить, как и когда правильно применять ООП в Python, эта книга для вас. Если вы объектно-ориентированный программист для других языков или ищете опору в новом мире Python 3.8, вы тоже найдете эту книгу полезным введением в Python. Предыдущий опыт работы с Python 3 не требуется.
С помощью следующего списка программного и аппаратного обеспечения вы можете запускать все файлы кода, представленные в книге (Глава 1-13).
Список программного и аппаратного обеспечения
Глава | Требуется программное обеспечение | Требуется ОС |
---|---|---|
2-13 | Python 3.5.2 и выше | Windows, Mac OS X и Linux (любая) |
Сопутствующие товары
Познакомьтесь с автором
Дасти Филлипс Канадский разработчик программного обеспечения и автор, в настоящее время проживающий в Нью-Брансуике.Он был активен в сообществе открытого исходного кода в течение двух десятилетий и программировал на Python почти столько же. Он имеет степень магистра компьютерных наук и работал в Facebook, ООН и нескольких стартапах. В настоящее время он изучает технологию сохранения конфиденциальности на сайте beanstalk.network.
Python 3 «Объектно-ориентированное программирование» было его первой книгой. Он также написал «Создание приложений в Киви» и самостоятельно опубликовал «Hacking Happy» — путешествие к психическому благополучию для технически подкованных людей.Скоро появится и художественная литература, так что следите за обновлениями!
Другие книги автора
Python 3 Объектно-ориентированное программирование — второе издание
Python 3 объектно-ориентированное программирование
Предложения и отзывы
Щелкните здесь, если у вас есть отзывы или предложения.
Объектно-ориентированное программирование на Python: изучение примеров
Это руководство описывает объектно-ориентированное программирование (ООП) на Python с примерами. Это пошаговое руководство, разработанное для людей, не имеющих опыта программирования.Объектно-ориентированное программирование популярно и доступно на других языках программирования, помимо Python, таких как Java, C ++, PHP.
Что такое объектно-ориентированное программирование?
В объектно-ориентированном программировании (ООП) вы можете гибко представлять в своем коде объекты реального мира, такие как автомобиль, животное, человек, банкомат и т. Д. Проще говоря, объект — это то, что обладает некоторыми характеристиками и может выполнять определенные функции. Например, автомобиль является объектом и может выполнять такие функции, как запуск, остановка, движение и торможение.Это функция автомобиля. А характеристики — это цвет автомобиля, пробег, максимальная скорость, год выпуска и т. Д. В приведенном выше примере автомобиль — это объект
. Функции называются методами
в мире ООП. Характеристики — это атрибуты (свойства)
. Технически атрибуты — это переменные или значения, связанные с состоянием объекта, тогда как методы — это функции, которые влияют на атрибуты объекта.
Используют ли специалисты по обработке данных объектно-ориентированное программирование?
Это один из самых распространенных вопросов, которые задают специалисты по данным перед изучением ООП. Когда дело доходит до обработки данных и машинного обучения с использованием Python, обычно рекомендуется изучать библиотеки pandas, numpy, matplotlib, scikit-learn. Эти библиотеки были написаны опытными разработчиками Python для автоматизации или упрощения большинства задач, связанных с наукой о данных.Все эти библиотеки зависят от ООП и его концепций. Например, вы строите регрессионную модель с помощью библиотеки scikit-learn. Сначала вы должны объявить свою модель как объект, а затем использовать подходящий метод. Не зная основ ООП, вы не сможете понять, почему вы пишете код таким образом.В Python существует в основном 3 стиля программирования: объектно-ориентированное программирование, функциональное программирование и процедурное программирование. Проще говоря, в Python есть 3 разных способа решения проблемы.Функциональное программирование наиболее популярно среди специалистов по данным, поскольку оно дает преимущество в производительности. ООП полезно, когда вы работаете с большими кодовыми базами, и очень важна возможность сопровождения кода.
Заключение: Хорошо изучать основы ООП, чтобы понимать, что стоит за библиотеками, которые вы используете. Если вы стремитесь стать отличным разработчиком Python и хотите создать библиотеку Python, вам необходимо изучить ООП (обязательно!). В то же время есть много специалистов по данным, которые не знают концепций ООП и все еще преуспевают в своей работе.
Основы: ООП в Python
В этом разделе мы подробно рассмотрим концепции, связанные с ООП в Python.Объект и класс
Класс — это архитектура объекта. Это правильное описание атрибутов и методов класса. Например, дизайн однотипной машины — это класс. Вы можете создать множество объектов из класса. Как будто из конструкции автомобиля можно сделать множество однотипных автомобилей.Существует множество реальных примеров классов, как описано ниже —
- Рецепт омлета класса.Омлет — это объект.
- Владелец банковского счета — это класс. Атрибуты: имя, фамилия, дата рождения, профессия, адрес и т. Д. Методы могут быть «Смена адреса», «Смена профессии», «Смена фамилии» и т. Д. «Смена фамилии» обычно применима к женщины, когда они меняют фамилию после замужества
- Собака класс. Атрибуты: порода, количество ног, размер, возраст, окрас и т. Д. Методы: есть, спать, сидеть, лаять, бегать и т. Д.
В python мы можем создать класс, используя ключевое слово class
.Метод класса может быть определен ключевым словом def
. Она похожа на обычную функцию, но определяется внутри класса и является функцией класса. Первым параметром в определении метода всегда является self
, а метод вызывается без параметра self
.
Пример 1: Создание класса автомобиля
-
класс
: вагон -
атрибуты
: год, миль на галлон и скорость -
методы
: ускорение и торможение -
объект
: вагон1
автомобиль класса: # атрибутов год = 2016 # год модели автомобиля миль на галлон = 20 # пробег speed = 100 # текущая скорость # методы def ускорение (self): вернуть машину.скорость + 20 def тормоз (сам): возврат вагона. скорость - 50
car1 = автомобиль () car1.accelerate () 120 car1.brake () 50 car1.year 2016 г. car1.mpg 20 car1.speed 100Для отправки методов нам нужно использовать скругленные скобки.
Пример 2: Создание класса компании
В приведенном ниже примере мы создаем класс под названием company. Здесь атрибуты: имя, оборот, выручка и количество сотрудников, работающих в компании. Метод — это доход, полученный на одного сотрудника (для демонстрации назовем его продуктивность , ).# Создает класс Company класс Компания: # атрибутов name = "XYZ Bank" оборот = 5000 доход = 1000 no_of_employees = 100 # метод def производительность (self): возврат Company.revenue / Company.no_of_employees
Атрибуты, которые определены вне метода, могут быть извлечены без создания объекта.
Название компании Выход «XYZ Bank» Компания. Оборот Выход 5000 Company.no_of_employees Выход 100 Компания().производительность () Выход 10.0
Конструктор
Конструктор — это особый метод. Вы можете думать об этом как о функции, которая инициализирует или активирует атрибуты или свойства класса для объекта. Используйте ключевое слово __init__
, чтобы создать метод для конструктора. В предыдущем разделе мы обсудили пример автомобиля как объекта. Вы можете думать о конструкторе как о всей последовательности действий, необходимых для того, чтобы фабрика конструировала объект автомобиля из шаблона проектирования класса. self
представляет тот объект, который наследует эти свойства. Объекты — это экземпляры класса. Слова «экземпляр» и «объект» взаимозаменяемы. Процесс создания объекта класса называется экземпляром
.
В следующем примере мы просим пользователя ввести значения. __init__
вызывается всякий раз, когда создается объект класса.
классный человек: def __init __ (я, имя, фамилия): себя.first = имя self.last = фамилия myname = person ("Дипаншу", "Бхалла") печать (myname.last)
Мы создали объектmyname
класса person.Когда вы создаете новый объект >>> вызывается метод __init__ >>> Поведение внутри метода__init__ выполняется
Возьмем другой пример. Здесь приведенная ниже программа возвращает вывод на основе метода, определенного в классе
.класс MyCompany: # методы def __init __ (собственное имя, имя компании, доход, размер сотрудника): себя.name = compname self.revenue = доход self.no_of_employees = размер сотрудников def производительность (self): вернуть self.revenue / self.no_of_employees MyCompany ('XYZ Bank', 1000,100) .productivity () Выход 10.0 MyCompany ('ABC Bank', 5000,200) .productivity () Выход 25,0
Альтернативный способ вызова метода класса
Банк = MyCompany ('ABC Bank', 5000,200) MyCompany.productivity (Банк)
Переменные
Атрибуты класса также называются переменными.Есть два типа переменных: одна объявлена внутри класса, но вне методов класса, а другая объявлена внутри __init__
. Когда вы используете метод __int__, вы можете получить доступ к переменным только после создания объекта. Эти переменные называются переменными экземпляра ,
или локальными переменными. Те, которые определены вне методов, называются переменными класса ,
или глобальными переменными. Вы можете получить доступ к этим переменным в любом месте класса. Смотрите разницу в примере ниже.
класс MyCompany: #Class Variable рост = 0,1 def __init __ (собственное имя, имя компании, доход, размер сотрудника): #Instance Variables self.name = compname self.revenue = доход self.no_of_employees = размер сотрудников MyCompany.growth 0,1
Как получить переменную дохода из класса MyCompany?
Неправильный путьMyCompany.revenueAttributeError: объект типа «MyCompany» не имеет атрибута «доход» Правильный способ
Банк = MyCompany ('DBA Bank', 50000, 1000) Банк.доход50000
MyCompany.revenue
возвращает ошибку, поскольку к нему невозможно получить доступ, поскольку объект не был создан.Методы
В python есть три типа методов: Instance, Class и Static.-
Экземпляр
принимаетself
в качестве первого аргумента. Их также называют объектом или обычным методом . Это тот же метод, который мы изучили в предыдущих разделах. -
Класс
принимаетcls
в качестве первого аргумента. cls относится к классу. Чтобы получить доступ к переменной класса в методе, мы используем декоратор@classmethod
и передаем класс методу . -
Статический
ничего не принимает в качестве первого аргумента. Он имеет ограниченное использование, которое объясняется в последней части этой статьи.
Чем отличаются методы экземпляра и класса?
Метод экземпляра может получить доступ к свойствам, уникальным для объекта или экземпляра. В то время как метод класса используется, когда вы хотите получить доступ к свойству класса, а не к свойству конкретного экземпляра этого класса.Другое отличие в стиле написания состоит в том, что метод Instance принимает self в качестве первого параметра, тогда как метод Class принимает cls в качестве первого параметра. В приведенном ниже примере мы создаем класс для cab
. И такси, и такси означают одно и то же. Атрибуты или свойства кабины — это имя водителя, количество километров пробега, место посадки и высадки, стоимость проезда и количество пассажиров, находящихся в кабине.
Здесь мы создаем 3 метода: rateperkm
, noofcabs
, avgnoofpassengers
.Первый — это метод экземпляра, а два других — методы класса.
-
rateperkm
возвращает стоимость проезда в такси за км, которая рассчитывается путем деления общей суммы счета на количество. км такси проехали. -
noofcabs
возвращает количество работающих кабин. Подумайте об агентстве такси, которое владеет большим количеством такси и хочет знать, сколько такси занято -
avgnoofpassengers
возвращает среднее количество пассажиров, путешествующих в автомобиле. Для расчета среднего значения учитываются все работающие кабины и количество пассажиров в каждой кабине.
класс Cab: # Инициализировать переменные для первой итерации numberofcabs = 0 numpassengers = 0 def __init __ (я, водитель, км, места, оплата, пассажиры): self.driver = драйвер self.running = кмс self.places = места self.bill = платить Cab.numberofcabs = Cab.numberofcabs + 1 Cab.numpassengers = Cab.numpassengers + пассажиры # Возврат стоимости проезда в такси за км def rateperkm (self): вернуть self.bill / self.running # Возвращает количество запущенных кабин @classmethod def noofcabs (cls): вернуть cls.количество кабин # Возвращает среднее количество пассажиров, путешествующих в кабине. @classmethod def avgnoofpassengers (cls): вернуть int (cls.numpassengers / cls.numberofcabs) firstcab = Cab ("Рамеш", 80, ['Дели', 'Нойда'], 2200, 3) secondcab = Cab ("Суреш", 60, ['Гургаон', 'Нойда'], 1500, 1) thirdcab = Cab ("Дэйв", 20, ['Гургаон', 'Нойда'], 680, 2) firstcab.driver 'Рамеш' secondcab.driver 'Суреш' третья кабина. водитель 'Дэйв'
первая кабина.rateperkm () 27,5 secondcab.rateperkm () 25,0 thirdcab.rateperkm () 34,0
Cab.noofcabs () 3 Cab.avgnoofpassengers () 2
Cab.avgnoofpassengers () возвращает 2, которое вычисляется по формуле (3 + 1 + 2) / 3
Статические методы
Статический метод — наименее популярный из всех трех методов. В отличие от методов экземпляра и класса, статический метод не принимает специальное ключевое слово (self, cls) в качестве первого параметра.Он имеет ограниченное использование, потому что вы также не можете получить доступ к свойствам экземпляра (объекта) класса, ИЛИ вы не можете получить доступ к атрибутам класса. Единственное использование — это можно вызвать без объекта. В основном это полезно для создания вспомогательных или служебных функций, таких как проверка имени драйвера (имя драйвера должно быть меньше 32 символов) или сумма счета должна быть больше нуля (не может быть отрицательной или нулевой). См. Программу ниже для той же задачи.класс Cab: @staticmethod def billvalidation (оплата): return int (оплата)> 0 Такси.биллвалидация (0,2) Выход Ложь
Наследование
Наследование использует код для класса Children , который уже был написан для класса Parent . Например, некоторые атрибуты класса транспортного средства такие же, как класс автомобиля, автобуса и грузовика. Атрибуты имени водителя, количества колес и т. Д. Одинаковы для всех классов. Автомобиль — это родительский класс
, а Автомобиль, автобус и грузовик — это дочерние классы
. В ООО это означает, что класс наследует атрибуты и методы поведения от своего родительского класса.- Создайте родительский класс
Транспортное средство
и используйте его атрибуты для дочернего классаТранспортное средство
. В приведенной ниже программе нам не нужно указывать атрибуты класса cab. Он унаследован от автомобиля.
класс Автомобиль: def __init __ (я, водитель, колеса, сиденья): self.driver = драйвер self.noofwheels = колеса self.noofseats = места класс Cab (Автомобиль): проходить cab_1 = Cab ('Сэнди', 4, 2) cab_1.driver Выход 'Сэнди'
Автомобиль
класс Автомобиль: минимальная скорость = 50 def __init __ (я, водитель, колеса, сиденья): себя.driver = водитель self.noofwheels = колеса self.noofseats = места класс Cab (Автомобиль): минимальная скорость = 75 Автомобиль. Минимальная 50 Кабина минимальная 75
Cab
и Bus
, которые имеют много похожих атрибутов, но есть несколько уникальных для класса. Чтобы решить эту проблему, мы создали родительский класс с именем Vehicle
, который содержит общие атрибуты и метод.класс Автомобиль: минимальная скорость = 50 def __init __ (я, водитель, колеса, сиденья, км, счет): self.driver = драйвер self.noofwheels = колеса self.noofseats = места self.running = кмс self.bill = счет def rateperkm (self): вернуть self.bill / self.running класс Cab (Автомобиль): минимальная скорость = 75 def __init __ (я, водитель, колеса, сиденья, км, счет, тип кабины): Автомобиль .__ init __ (сам, водитель, колеса, сиденья, км, счет) self.category = cabtype класс Автобус (Автомобиль): минимальная скорость = 25 def __init __ (я, водитель, колеса, сиденья, км, счет, цвет): Транспортное средство.__init __ (я, водитель, колеса, сиденья, км, счет) self.color = цвет cab_1 = Cab ('Prateek', 4, 3, 50, 700, 'внедорожник') cab_1.category cab_1.rateperkm () bus_1 = Автобус ('Дэйв', 4, 10, 50, 400, 'зеленый') bus_1.color bus_1.rateperkm ()
Мы можем заменить эту командуVehicle .__ init __ (self, driver, wheels, seat, km, bill)
наsuper () .__ init __ (driver, wheels, seat, km, bill)
.
super ()
используется для ссылки на родительские атрибуты и методы.
Полиморфизм
Полиморфизм означает способность принимать различные формы.Это важная концепция, когда вы имеете дело с дочерним и родительским классами. Полиморфизм в python применяется через переопределение метода и перегрузку метода .Переопределение метода
Переопределение метода позволяет нам иметь метод в дочернем классе с тем же именем, что и в родительском классе, но определение метода дочернего класса отличается от метода родительского класса.класс Автомобиль: сообщение def (self): print ("Метод родительского класса") класс Cab (Автомобиль): сообщение def (self): print ("Метод дочернего класса Cab") класс Автобус (Автомобиль): сообщение def (self): print ("Метод класса дочерней шины") x = Автомобиль () Икс.сообщение() Метод родительского класса y = Кабина () y.message () Метод класса Child Cab z = Автобус () z.message () Метод класса "Детский автобус"Как вы можете видеть на выходе, показанном выше, дочерние классы переопределяют метод родительского класса.
Перегрузка метода
Он позволяет вам гибко определять функцию или метод, так что вы можете вызывать их только с некоторыми аргументами и не нужно указывать другие аргументы. Вы также можете вызвать его со всеми аргументами. Вы можете делать это как хотите. В приведенном ниже скрипте метод может быть вызван без параметра (игнорируя параметр фразы). Или это может быть вызвано параметром фразой
.
сообщение класса: def подробности (self, фраза = None): если фраза не None: print ('Мое сообщение -' + фраза) еще: print ('Добро пожаловать в мир Python') # Объект x = Сообщение () # Вызываем метод без параметра x.details () # Вызываем метод с параметром x.details («Жизнь прекрасна»)
Что такое __str__?
Он используется для создания удобочитаемого представления объекта.класс Автомобиль: def __init __ (я, водитель, колеса, сиденья): self.driver = драйвер self.noofwheels = колеса self.noofseats = места veh_1 = Автомобиль («Сэнди», 4, 2) печать (veh_1) Выход __main __. Объект Vehicle по адресу 0x0000019ECCCA05F8
класс Автомобиль: def __init __ (я, водитель, колеса, сиденья): self.driver = драйвер self.noofwheels = колеса self.noofseats = места def __str __ (сам): вернуть «Имя драйвера:» + self.водитель + ";" + "Кол-во мест в кабине:" + str (авт. сид.) veh_1 = Автомобиль («Сэнди», 4, 2) печать (veh_1) Выход Имя водителя: Сэнди; Количество мест в кабине: 2
Инкапсуляция данных
Инкапсуляция данных означает ограничение доступа к методам и переменным. Это может предотвратить случайное (ошибочное) изменение данных.- Когда мы используем два символа подчеркивания ‘__’ перед именем атрибута, это делает атрибут недоступным вне класса.Он становится частным атрибутом , что означает, что вы не можете читать и записывать эти атрибуты, кроме как внутри класса. Обычно он используется разработчиком модуля.
- Если вы не используете подчеркивание перед атрибутом, это открытый атрибут , к которому можно получить доступ внутри или вне класса.
класс Квартира: def __init __ (сам): self.type = "премиум" self .__ bhk = "3 BHK" flat_1 = Квартира () flat_1.type премия flat_1 .__ bhk AttributeError: объект 'Flat' не имеет атрибута '__bhk'В приведенной выше программе type — это общедоступный атрибут, а bhk — частный атрибут, к которому нельзя получить доступ вне класса.
Геттеры и сеттеры
Они используются для получения и обновления значения переменной. Сеттер — это метод, обновляющий значение переменной. Getter — это метод, считывающий значение переменной. Давайте узнаем это на примерах.класс Автомобиль: def __init __ (self, имя_драйвера, имя_последнего_драйвера): self.fdriver = имя_драйвера self.ldriver = имя_последнего_драйвера self.email = self.fdriver + '.' + self.ldriver + '@ uber.com' veh_1 = Автомобиль («Сэнди», «Стюарт») veh_1.fdriver Сэнди veh_1.email '[email protected]'Здесь мы обновляем имя драйвера, но это не влияет на адрес электронной почты, который представляет собой комбинацию имени и фамилии.
veh_1.fdriver = 'Том' veh_1.fdriver 'Томь' veh_1.email '[email protected]'Имя было изменено с Сэнди на Тома, но адрес электронной почты остался прежним. Ладно, возникает очевидный вопрос «а как обновить адрес электронной почты?». С помощью декоратора
@property
мы можем изменить поведение электронной почты. email (self)
— это метод, но он работает как обычное свойство. Этот специальный метод называется Getters and Setters
.класс Автомобиль: def __init __ (self, имя_драйвера, имя_последнего_драйвера): self.fdriver = имя_драйвера self.ldriver = имя_последнего_драйвера @имущество def email (self): вернуть self.fdriver + '.' + self.ldriver + '@ uber.com' veh_1 = Автомобиль («Сэнди», «Стюарт») veh_1.fdriver = 'Том' veh_1.email '[email protected] '
Как обновить имя и фамилию автоматически при изменении адреса электронной почты
класс Автомобиль: def __init __ (self, имя_драйвера, имя_последнего_драйвера): self.fdriver = имя_драйвера self.ldriver = имя_последнего_драйвера @имущество def email (self): вернуть self.fdriver + '.' + self.ldriver + '@ uber.com' @ email.setter электронная почта def (сам, адрес): first = адрес [: address.find ('.')] last = адрес [address.find ('.') +1: address.find (' @ ')] self.fdriver = первый self.ldriver = последний veh_1 = Автомобиль («Сэнди», «Стюарт») veh_1.email = '[email protected]' veh_1.fdriver 'глубокий' veh_1.ldriver 'bhalla'
Проверка
В реальном мире геттеры и сеттеры в основном используются для включения логики проверки. В приведенном ниже примере мы создаем класс пожертвований с атрибутом amount. Сумма должна быть от 10 до 1 000 000. Если пользователь вводит меньше 10, оно должно быть установлено как 10.Точно так же, если пользователь пытается ввести значение больше 1 миллиона, оно должно быть ограничено только 1 миллионом.пожертвование класса: def __init __ (self, количество): self.amount = количество @имущество сумма определения (самостоятельно): вернуть self .__ amount @ amount.setter def amount (self, amount): если сумма 1000000: self .__ amount = 1000000 еще: self .__ amount = количество благотворительность = пожертвование (5) charity.amount 10
Как импортировать класс
В этом разделе мы расскажем, как загрузить класс из другого файла или каталога.- Сохраните следующий сценарий как
Mymodule.py
- В приведенном ниже коде укажите каталог, в котором хранится файл
Mymodule.py
- Создайте объект или запустите методы, как обычно. Обязательно добавьте имя модуля в качестве префикса перед использованием класса и метода класса
"" " Класс автомобиля "" " класс Cab: #Initialise для первой итерации numberofcabs = 0 def __init __ (сам, водитель, км, оплата): self.driver = драйвер self.running = кмс self.bill = платить Cab.numberofcabs = Cab.numberofcabs + 1 # Средняя стоимость возврата за км def rateperkm (self): вернуть self.bill / self.running # Возвращает количество запущенных кабин @classmethod def noofcabs (cls): вернуть cls.количество кабин если __name__ == "__main__": #Cab class firstcab = Cab ("Рамеш", 80, 1200) Атрибут #driver в классе Cab печать (firstcab.driver) #class method печать (Cab.noofcabs ())
импорт ОС os.chdir ("C: / Users / DELL / Desktop /") импортировать Mymodule
#Cab класс в Mymodule.ру firstcab = Mymodule.Cab ("Рамеш", 80, 1200) Атрибут #driver в классе кабины firstcab.driver #rateperkm метод экземпляра в Mymodule2.py firstcab.rateperkm () #noofcabs classmethod в Mymodule2.py Mymodule.Cab.noofcabs ()Чтобы избежать записи имени модуля для доступа к классу, вы можете использовать «from», которое загружает модуль в текущее пространство имен.
из Mymodule import * firstcab = Cab ("Сэнди", 80, ['Дели', 'Нойда'], 1200, 3)
Что такое __name__ == «__main__»?
Любой код внутри if __name__ == '__main__':
будет выполнен, когда вы запустите ваш.py файл напрямую (с терминала).
Если вы импортируете модуль import Mymodule
, код внутри if __name__ == '__main__':
не будет запущен.
если __name__ == '__main__': print ('Первый результат') еще: print ('Второй результат')
Как изменить каталог в командной строке
Введите cd , затем пробел и имя папки.После установки правильного каталога вы можете ввести имя вашего файла скрипта Python. См. Снимок ниже.Упражнение
Создайте класс Rectangle
, который имеет атрибуты length и width. Создайте 2 метода вычисления площади прямоугольника и периметра прямоугольника. Площадь рассчитывается умножением длины на ширину. Периметр в 2 раза больше (длина + ширина). Решите и опубликуйте свое решение в поле для комментариев.После завершения этого руководства вы должны иметь хорошее представление о важных темах объектно-ориентированного программирования, используемых в Python.Следующим шагом будет практика освоенных вами понятий. Попробуйте использовать его в своих живых проектах.
Понимание O.O.P. в Python с одной статьей | Джулиан Эррера
Чтобы начать понимать интуицию, лежащую в основе этой техники программирования, давайте взглянем на начальный пример. Представьте, что вам нужно описать машину кому-то, кто никогда ее раньше не видел. Как бы вы это сделали?
Фото vaea Garrido на UnsplashВы можете начать говорить, что это колесный автомобиль, используемый для перевозки.Кроме того, можно сказать, что существует несколько брендов компаний-производителей автомобилей, которые производят разные типы автомобилей, отвечающие различным потребностям. На еще более базовом уровне вы могли бы сказать, что у него четыре шины, что они в большинстве случаев перевозят до пяти человек и что они в основном используются для перевозки людей, а не товаров.
Объясняя компьютеру, что это за объект, неплохо подойти к нему аналогичным образом. Компьютеры не имеют врожденного представления о том, что такое автомобиль, для чего они были созданы и кто ими пользуется.И если вы хотите, чтобы ваш компьютер правильно понимал объект, в данном случае автомобиль, вы должны четко объяснить, каковы его атрибуты .
Чтобы облегчить компьютерам понимание этих новых концепций, Python использует шаблон программирования под названием объектно-ориентированное программирование , который моделирует концепции с помощью классов и объектов. Это гибкая и мощная парадигма, в которой классы представляют и определяют концепции, а объектов являются экземплярами классов .В примере с автомобилем мы можем создать класс с именем car , который определяет его характеристики для компьютера. Мы могли бы создать тысячи экземпляров этого класса car , которые являются отдельными объектами этого класса.
Идея объектно-ориентированного программирования может показаться абстрактной и сложной, но если вы запрограммировали какое-либо программное обеспечение, вы, возможно, уже использовали объекты, даже не осознавая этого. Почти все в Python представляет собой объект , все числа, строки, списки и словари включены в этот тип элемента.Основная концепция объектно-ориентированного программирования сводится к атрибутам и методам , связанным с типом:
- Атрибуты — это характеристики, связанные с типом.
- Методы — это функции, связанные с типом.
В примере с автомобилем цвет и марка — это два атрибута, связанных с каждым экземпляром или автомобилем, созданным с помощью программы. С другой стороны, методы — это действия, выполняемые автомобилем или автомобилем, например, вождение.Более ориентированным на компьютер примером может быть файл в каталоге, поскольку каждый файл имеет имя, размер и дату создания.
Как вы можете видеть на изображении выше, когда мы используем функцию типа , как мы только что сделали здесь, Python сообщает нам, к какому классу принадлежит значение или переменная. А поскольку целых чисел и строк являются классами, с ними связано множество атрибутов и методов. Вы можете получить доступ к атрибутам и методам класса с помощью функции dir в Python, как показано ниже:
В моей предыдущей статье о строках я исследовал множество методов и атрибутов класса строк.Взгляните на него, чтобы получить дополнительные сведения о том, как обращаться с объектами строк, которые в этом случае будут другим экземпляром класса строк. Это означает, что все они имеют одинаковые методы, хотя содержимое строки отличается.
Почему существует множество методов, которые начинаются и заканчиваются двойным подчеркиванием?
Они называются специальными методами , и их обычно не вызывают такими странными именами. Вместо этого они вызываются некоторыми внутренними функциями Python.например, метод __len__ вызывается функцией len .
Если вы хотите узнать, что делает конкретный метод, вам следует использовать функцию help :
Когда мы используем функцию help для любой переменной или значения, мы получаем доступ ко всей документации для соответствующего класса. В этом случае мы смотрим на документацию для классов str и int .
Хотя Python поставляется с множеством предопределенных классов для нас, мощь объектно-ориентированного программирования проявляется тогда, когда мы определяем наши собственные классы с их собственными атрибутами и методами.
Как упоминалось ранее, цель объектно-ориентированного программирования — помочь определить реальную концепцию таким образом, чтобы ее понимал компьютер. Давайте приступим к созданию нового класса на примере автомобиля:
Давайте проясним конкретные элементы кода:
- В Python мы используем зарезервированное ключевое слово class , чтобы сообщить компьютеру, что мы запускаем новый класс. . За ним следует имя класса и двоеточие. Руководства по стилю Python рекомендуют, чтобы имена классов начинались с заглавной буквы .В моем случае класс называется Car .
- После строки с определением класса идет тело класса с отступом вправо по шаблону циклов или функций.
- Мы рассмотрим специальные методы init и repr в четвертом разделе этой статьи.
Как мы можем расширить наше определение класса Car? Вероятно, он будет иметь те же атрибуты, которые представляют информацию, которую мы хотим связать с автомобилем, например марку и цвет.
Теперь приступим к созданию экземпляра класса Car и присвоим его переменной с именем «my_car». Чтобы создать новый экземпляр любого класса, мы вызываем имя класса, как если бы это была функция:
Как видите, я передаю в качестве аргумента марку и цвет, поскольку я настроил свой класс на требуются оба элемента при создании нового объекта класса. В результате мы можем вызвать атрибуты созданного экземпляра и получить ранее присвоенное значение:
Синтаксис, используемый для доступа к атрибутам, называется точечной нотацией из-за точки, используемой в выражении.Точечная запись позволяет получить доступ к любым возможностям объекта, например к бренду или цвету.
Атрибуты и методы некоторых объектов могут быть другими объектами и могут иметь собственные атрибуты и методы. Например, мы могли бы использовать методы upper или the capitalize для изменения обоих строковых атрибутов моего экземпляра:
До сих пор мы создали один экземпляр класса Car и установили его атрибуты. Теперь мы могли бы создать новый экземпляр класса с другими атрибутами:
Методы, по сути, вызываются для того, чтобы объекты выполняли какие-то действия.Например, верхний и заглавные для строк. Ключ к познанию интуиции методов в O.O.P. это понимать, что методы — это функции, которые работают с атрибутами конкретного экземпляра класса . Когда мы вызываем метод lower для строки, мы переводим содержимое этой конкретной строки в нижний регистр.
Давайте рассмотрим подробнее, создав новый класс с именем Dog и определив наши собственные методы. Во-первых, нам нужно определить класс и создать его экземпляр, как мы делали это раньше с классом Car.Хотя моя собака может быть отличной, она не может выполнять никаких действий, пока я не определю для нее методы. Взгляните на пример:
Как показано на изображении, мы должны начать определение метода с помощью ключевого слова def , как если бы мы делали это для функции, и сделать отступ справа от тела метода, как если бы мы для функции.
Функция получает параметр под названием «self». Этот параметр представляет экземпляр, в котором выполняется метод.
Даже если моя собака лает, она всегда будет делать это одинаково.Мы можем изменить то, как он будет лаять, с помощью простой модификации кода, чтобы получить гибкость в атрибутах и методах, которые мы настраиваем для наших классов:
Оба класса, созданные до этого параграфа, содержат значения по умолчанию как атрибуты и методы. Это не идеальный сценарий, поскольку он создает избыточный код для каждого атрибута и, что более важно, , так как очень легко забыть установить важное значение .
Итак, при написании кода рекомендуется установить атрибуты и методы, которые будут меняться в зависимости от экземпляра при создании класса, чтобы гарантировать, что каждый экземпляр содержит одни и те же важные атрибуты.Для этого нам нужно использовать специальный метод под названием Constructor .
Конструктор класса — это метод, который вызывается при вызове имени класса. Он всегда называется init .
Он содержит ключевое слово self, которое относится к создаваемому экземпляру, и аргументы, которые будут переданы программистом как атрибуты после создания экземпляра, как мы это делаем в примере ниже:
Второй метод class — это метод repr , который сообщает Python печатать предопределенный оператор каждый раз, когда вызывается экземпляр класса, как на изображении выше.
Хотите знать, какая функция у того или иного метода? См. Ранее введенную функцию help . Поскольку встроенные классы включают руководство, помогающее пользователям понять интуицию, лежащую в основе каждого метода или атрибута, мы также можем сделать это для наших собственных классов, методов и функций. Мы можем сделать это, добавив Docstring .
Строка документации — это краткий текст, объясняющий, что что-то делает.
Включив документацию в свои классы и объекты, вы получите гораздо больше информации о созданных методах, которые облегчат повторное использование кода и помогут другим пользователям понять его.Помните, что строка документации всегда должна иметь отступ на том же уровне блока, который она документирует.
Еще одним важным аспектом объектно-ориентированного программирования является Наследование . Точно так же, как у людей есть родители, бабушки и дедушки и т. Д., У объектов есть предки. Принцип наследования позволяет программисту строить отношения между концепциями и группировать их вместе. В частности, это позволяет нам уменьшить дублирование кода за счет обобщения нашего кода.
Например, как мы можем определить представление « других транспортных средств» отдельно от машины, которую мы уже создали, или других домашних животных, кроме моей собаки.Эта характеристика группирования позволяет нам создавать другие классы, которые разделяют некоторые атрибуты существующих классов, но не все из них, чтобы добавлять другие похожие экземпляры без перезаписи существующего кода.
В Python мы используем круглые скобки в объявлении класса, чтобы показать отношение наследования . В приведенном выше примере транспортировки я использовал синтаксис Python, чтобы сообщить компьютеру, что и автомобиль, и поезд наследуются от класса MyTransports. Из-за этого у них автоматически есть один и тот же конструктор, который устанавливает атрибуты цвета и бренда.
С помощью метода наследования мы можем использовать класс транспорта для хранения информации, которая применяется ко всем доступным видам транспорта, и сохранять атрибуты, специфичные для автомобилей или поездов, в их собственных классах. Вы можете рассматривать класс MyTransports как родительский класс, а классы Car и Train как братьев и сестер.
Примером, который ближе к задачам, которые вы выполняете в ИТ-отделе, может быть система, которая обслуживает сотрудников вашей компании. У вас может быть класс с именем employee , который может иметь атрибуты для таких вещей, как , полное имя человека, имя пользователя , используемое в системах компании, группы , к которым принадлежит сотрудник, и так далее.В системе также может быть класс менеджера, который также является сотрудником, но с ним связана дополнительная информация, например, сотрудники, которые подчиняются определенному менеджеру.
Объектно-ориентированное программирование Python | Концепции ООП Python
Объектно-ориентированное программирование как дисциплина приобрело всеобщее поклонение среди разработчиков. Python, востребованный язык программирования, также следует парадигме объектно-ориентированного программирования. Он занимается объявлением классов и объектов Python, которые закладывают основу концепций ООП.Эта статья о «Python объектно-ориентированного программирования» проведет вас через объявление классов Python, создание экземпляров объектов из них вместе с четырьмя методологиями ООП.
В этой статье будут подробно рассмотрены следующие аспекты:
Приступим.
Что такое объектно-ориентированное программирование? (Концепции ООП в Python)
Объектно-ориентированное программирование — это способ компьютерного программирования, использующий идею «объектов» для представления данных и методов.Это также подход, используемый для создания аккуратного и многоразового кода вместо избыточного. программа разбита на автономные объекты или несколько мини-программ. Каждый индивидуальный объект представляет собой отдельную часть приложения, имеющую собственную логику и данные для взаимодействия внутри себя.
Теперь, чтобы получить более ясное представление о том, почему мы используем oops вместо pop, я перечислил ниже различия.
Разница между объектно-ориентированным и процедурно-ориентированным программированиемОбъектно-ориентированное Программирование (ООП) | Это восходящий подход | Это нисходящий подход |
Программа разделена на объекты | Программа разделена на функции | |
Использует Access модификаторы ‘public’, private ‘, protected’ | Не использует Модификаторы доступа | |
Более безопасный | Менее безопасный | |
Данные могут свободно перемещаться из функции n для работы в программах | ||
Он поддерживает наследование | Он не поддерживает наследование |
Это все о различиях, продвигаясь вперед, давайте разберемся с Python OOP Conceots.
Что такое концепции ООП Python?Основные концепции ООП (объектно-ориентированного программирования) в Python включают класс, объект, метод, наследование, полиморфизм, абстракцию данных и инкапсуляцию.
Вот и все о различиях, забегая вперед, давайте разберемся с классами и объектами.
Что такое классы и объекты?
Класс — это набор объектов, или можно сказать, что это план объектов, определяющих общие атрибуты и поведение.Возникает вопрос, как это сделать?
Что ж, он логически группирует данные таким образом, что повторное использование кода становится простым. Я могу привести вам пример из реальной жизни: представьте, что офисный «сотрудник» представляет собой класс, а все атрибуты, связанные с ним, такие как «emp_name», «emp_age», «emp_salary», «emp_id», являются объектами в Python. Давайте посмотрим с точки зрения кодирования, как создать экземпляр класса и объекта.
Класс определяется ключевым словом «Класс».
Пример:
class class1 (): // class 1 - это имя класса
Примечание. Python не чувствителен к регистру.
Объекты:Объекты являются экземпляром класса. Это сущность, у которой есть состояние и поведение. Вкратце, это экземпляр класса, который может получить доступ к данным.
Синтаксис: obj = class1 ()
Здесь obj — это «объект» class1.
Создание объекта и класса в python:Пример:
class employee (): def __init __ (self, name, age, id, salary): // создание функции себя.name = name // self - это экземпляр класса self.age = возраст self.salary = зарплата self.id = id emp1 = employee ("harshit", 22,1000,1234) // создание объектов emp2 = сотрудник ("арджун", 23,2000,2234) print (emp1 .__ dict __) // Распечатывает словарь
Объяснение: ’emp1′ и ’emp2′ — это объекты, экземпляры которых создаются для класса «employee». Здесь слово (__dict__) представляет собой «словарь», который печатает все значения объекта «emp1» против заданный параметр (имя, возраст, зарплата).(__init__) действует как конструктор, который вызывается всякий раз, когда создается объект.
Надеюсь, теперь вы, ребята, не столкнетесь с какими-либо проблемами при работе с «классами» и «объектами» в будущем.
Итак, позвольте мне познакомить вас с методологиями объектно-ориентированного программирования:
Методологии объектно-ориентированного программирования:Методологии объектно-ориентированного программирования имеют дело со следующими концепциями.
- Наследование
- Полиморфизм
- Инкапсуляция
- Абстракция
Давайте подробно разберемся с первой концепцией наследования.
Наследование:Когда-либо слышали об этом диалоге от родственников «вы выглядите в точности как ваш отец / мать». Причина этого называется «наследование». С точки зрения программирования это обычно означает «наследование или передачу характеристик от родительского к дочернему классу без каких-либо изменений». Новый класс называется производным / дочерним классом , а тот, от которого он является производным, называется родительским / базовым классом .
Давайте разберемся с каждой из подтем подробно.
Одиночное наследование:Одноуровневое наследование позволяет производному классу наследовать характеристики от единственного родительского класса.
Пример:
class employee1 (): // Это родительский класс def __init __ (я, имя, возраст, зарплата): self.name = имя self.age = возраст self.salary = зарплата class childemployee (employee1): // Это дочерний класс def __init __ (я, имя, возраст, зарплата, идентификатор): self.name = имя self.age = возраст self.salary = зарплата себя.id = id emp1 = employee1 ('суровый', 22,1000) печать (emp1.age)
Выход : 22
Объяснение:
Я беру родительский класс и создал конструктор (__init__), сам класс инициализирует атрибуты параметрами (‘name’, ‘age’ и ‘salary ‘).
Создан дочерний класс childemployee, который наследует свойства от родительского класса, и, наконец, созданы экземпляры объектов emp1 и emp2 в соответствии с параметрами.
Наконец, я напечатал возраст emp1. Что ж, вы можете делать кучу всего, например, распечатать весь словарь, или имя, или зарплату.
Многоуровневое наследование позволяет производному классу наследовать свойства от непосредственного родительского класса, который, в свою очередь, наследует свойства от своего родительского класса.
Пример:
класс employee (): // Суперкласс def __init __ (я, имя, возраст, зарплата): себя.name = имя self.age = возраст self.salary = зарплата class childemployee1 (employee): // Первый дочерний класс def __init __ (я, имя, возраст, зарплата): self.name = имя self.age = возраст self.salary = зарплата class childemployee2 (childemployee1): // Второй дочерний класс def __init __ (я, имя, возраст, зарплата): self.name = имя self.age = возраст self.salary = зарплата emp1 = сотрудник ('суровый', 22,1000) emp2 = childemployee1 ('арджун', 23,2000) печать (emp1.age) печать (emp2.age)
Вывод: 22,23
Объяснение:
Это четко объяснено в коде, написанном выше. Здесь я определил суперкласс как сотрудник, а дочерний класс как childemployee1.Теперь childemployee1 действует как родитель для childemployee2.
Я создал два объекта emp1 и emp2, где я передаю параметры «имя», «возраст», «зарплата» для emp1 из суперкласса «сотрудник» и «имя», «возраст,« зарплата ». »И« id »из родительского класса« childemployee1 »
Наследование на иерархическом уровне позволяет более чем одному производному классу наследовать свойства родительского класса.
Пример:
класс сотрудника (): def __init __ (я, имя, возраст, зарплата): // Иерархическое наследование self.name = имя self.age = возраст self.salary = зарплата класс childemployee1 (сотрудник): def __init __ (я, имя, возраст, зарплата): self.name = имя self.age = возраст self.salary = зарплата класс childemployee2 (сотрудник): def __init __ (я, имя, возраст, зарплата): self.name = имя self.age = возраст self.salary = зарплата emp1 = сотрудник ('суровый', 22,1000) emp2 = сотрудник ('арджун', 23,2000) печать (emp1.возраст) печать (emp2.age)
Вывод: 22,23
Пояснение:В приведенном выше примере вы можете ясно видеть, что существует два дочерних класса «childemployee1» и «childemployee2». Они наследуют функции от общего родительского класса, который называется «служащий».
Объекты emp1 и emp2 создаются по параметрам «имя», «возраст», «зарплата».
Многоуровневое наследование позволяет одному производному классу наследовать свойства более чем одного базового класса.
Пример:
class employee1 (): // Родительский класс def __init __ (я, имя, возраст, зарплата): self.name = имя self.age = возраст self.salary = зарплата class employee2 (): // Родительский класс def __init __ (я, имя, возраст, зарплата, идентификатор): self.name = имя self.age = возраст self.salary = зарплата self.id = id класс childemployee (сотрудник1, сотрудник2): def __init __ (я, имя, возраст, зарплата, идентификатор): self.name = имя self.age = возраст себя.зарплата = зарплата self.id = id emp1 = employee1 ('суровый', 22,1000) emp2 = сотрудник2 ('арджун', 23,2000,1234) печать (emp1.age) печать (emp2.id)
Вывод: 22,1234
Объяснение: В приведенном выше примере я взял два родительских класса «employee1» и «employee2». И дочерний класс «childemployee», который наследует оба родительских класса путем создания экземпляров объектов. ’emp1′ и ’emp2′ против параметров родительских классов.
Речь шла о наследовании, продвижении вперед в объектно-ориентированном программировании Python, давайте углубимся в «полиморфизм».
Полиморфизм:
Вы все должны были использовать GPS для навигации по маршруту. Разве не удивительно, сколько разных маршрутов вы встретите для одного и того же пункта назначения в зависимости от трафика, с точки зрения программирования это называется ‘ полиморфизм’. Это одна из таких методологий ООП, в которой одну задачу можно выполнять несколькими способами. Проще говоря, — это свойство объекта, которое позволяет ему принимать несколько форм .
Полиморфизм бывает двух типов:
- Полиморфизм во время компиляции
- Полиморфизм во время выполнения
Пример:
класс employee1 (): def имя (сам): print ("Жестокое его имя") def зарплата (самостоятельно): print («3000 - его зарплата») def age (self): print («ему 22 года») класс employee2 (): def имя (сам): print («Рахул - его имя») def зарплата (самостоятельно): print («4000 - его зарплата») def age (self): print («ему 23 года») def func (obj): // Перегрузка метода obj.name () obj.salary () объектвозраст() obj_emp1 = сотрудник1 () obj_emp2 = сотрудник2 () func (obj_emp1) func (obj_emp2)
Вывод:
Харшит — его имя
3000 — его зарплата
22 — его возраст
Рахул — его имя
4000 — его зарплата
23 — его возраст
Пояснение:
В приведенном выше В программе я создал два класса «employee1» и «employee2» и создал функции для «name», «salary» и «age» и распечатал их значения, не принимая их у пользователя.
Теперь добро пожаловать в основную часть, где я создал функцию с параметром «obj» и вызвал все три функции, то есть «имя», «возраст» и «зарплата».
Позже были созданы экземпляры объектов emp_1 и emp_2 для двух классов и просто вызвана функция. Такой тип называется перегрузкой метода, который позволяет классу иметь более одного метода с одним и тем же именем.
Полиморфизм во время выполнения также называется динамическим полиморфизмом, где он разрешается во время выполнения.Одним из распространенных примеров полиморфизма времени выполнения является «переопределение метода». Позвольте мне показать вам пример для лучшего понимания.
Пример:
класс сотрудника (): def __init __ (я, имя, возраст, идентификатор, зарплата): self.name = имя self.age = возраст self.salary = зарплата self.id = id def зарабатывать (самостоятельно): проходить класс childemployee1 (сотрудник): def заработать (self): // полиморфизм времени выполнения print ("денег нет") класс childemployee2 (сотрудник): def зарабатывать (самостоятельно): print ("есть деньги") c = childemployee1 c.заработать (сотрудник) d = childemployee2 d.earn (сотрудник)
Вывод: нет денег, есть деньги
Объяснение: В приведенном выше примере я создал два класса childemployee1 и childemployee2, которые являются производными от одного и того же базового класса employee. не получил денег, тогда как другой получает. Теперь главный вопрос: как это произошло? Итак, если вы присмотритесь, я создал пустую функцию и использовал Pass (оператор, который используется, когда вы не хотите выполнять какую-либо команду или код).Теперь, в двух производных классах, я использовал одну и ту же пустую функцию и использовал оператор печати как «нет денег» и «имеет деньги». Наконец, создал два объекта и вызвал функцию.
Переходя к следующей методологии объектно-ориентированного программирования Python, я расскажу об инкапсуляции.
Инкапсуляция:В необработанном виде инкапсуляция в основном означает связывание данных в одном классе. В Python, в отличие от Java, нет закрытых ключевых слов. К классу не следует обращаться напрямую, его следует указывать в виде префикса в виде подчеркивания.
Позвольте мне показать вам пример для лучшего понимания.
Пример:
класс сотрудника (объект): def __init __ (сам): self.name = 1234 self._age = 1234 self .__ salary = 1234 объект1 = сотрудник () печать (object1.name) печать (объект1._age) печать (объект1 .__ зарплата)
Вывод:
1234
Отслеживание (последний вызов последним):
1234
Файл «C: /Users/Harshit_Kant/PycharmProjects/test1/venv/encapsu.py», строка 10, в
print (object1.__salary)
AttributeError: Объект «employee» не имеет атрибута «__salary»
Explanation: Вы получите этот вопрос, что такое подчеркивание и ошибка? Ну, класс python обрабатывает частные переменные как (__ salary), к которым нельзя получить прямой доступ.
Итак, в моем следующем примере я использовал метод установки, который обеспечивает косвенный доступ к ним.
Пример:
класс сотрудника (): def __init __ (сам): self .__ maxearn = 1000000 def зарабатывать (самостоятельно): print ("заработок: {}".формат (self .__ maxearn)) def setmaxearn (self, заработать): // метод установки, используемый для доступа к закрытому классу self .__ maxearn = зарабатывать emp1 = сотрудник () emp1.earn () emp1 .__ maxearn = 10000 emp1.earn () emp1.setmaxearn (10000) emp1.earn ()
Выход:
доход: 1000000, доход: 1000000, доход: 10000
Пояснение: Использование метода установки обеспечивает косвенный доступ к методу частного класса . Здесь я определил класс сотрудника и использовал (__maxearn), который представляет собой метод установки, используемый здесь для хранения максимального заработка сотрудника, и функцию установки setmaxearn (), которая принимает цену в качестве параметра.
Это наглядный пример инкапсуляции, когда мы ограничиваем доступ к методу частного класса, а затем используем метод установки для предоставления доступа.
Далее в методологии объектно-ориентированного программирования Python рассказывает об одной из ключевых концепций, называемой абстракцией.
Абстракция:
Предположим, вы заказали билет в кино на букмекерской конторе с помощью сетевого банкинга или любого другого процесса. Вы не знаете, как создается пин-код или как выполняется проверка.С точки зрения программирования это называется «абстракцией». В основном это означает, что вы показываете только детали реализации конкретного процесса и скрываете детали от пользователя. Он используется для упрощения сложных задач путем моделирования классов, соответствующих проблеме.
Невозможно создать экземпляр абстрактного класса, что просто означает, что вы не можете создавать объекты для этого типа класса. Его можно использовать только для наследования функциональных возможностей.
Пример:
из abc import ABC, abstractmethod класс сотрудника (ABC): def emp_id (self, id, name, age, salary): // Абстракция проходить класс childemployee1 (сотрудник): def emp_id (self, id): print ("emp_id - 12345") emp1 = childemployee1 () emp1.emp_id (идентификатор)
Выходные данные : emp_id — 12345
Объяснение: Как вы можете видеть в приведенном выше примере, мы импортировали абстрактный метод, а остальная часть программы имеет родительский и производный классы. Создается экземпляр объекта для базового класса «childemployee», и используются функциональные возможности абстрактного.
Является ли Python на 100% объектно-ориентированным?Python не имеет спецификаторов доступа, таких как «частный», как в java. Он поддерживает большинство терминов, связанных с «объектно-ориентированным» языком программирования, за исключением строгой инкапсуляции.Следовательно, он не полностью объектно-ориентирован.