Как пользоваться классами в Python

Сегодня разберемся в основных аспектах разработки программ c применением классов в Python. Если опыт работы с объектно-ориентированным типом разработки программ у вас отсутствует, то давайте сначала разберем базовые нюансы.

ООП – что это такое?

Python – это язык программирования, являющийся объектно-ориентированным. Это наиболее простая и удобная категория языков разработки приложений, позволяющая не вникать в тончайшие детали того, как устроена та или иная возможность. Более того, сам формат объектов позволяет заимствовать готовые решения и ускорять таким образом разработку приложений. Объектно-ориентированное программирование сокращенно обозначается аббревиатурой ООП. 

Как правильно создавать классы в Python?

Для начала следует разработаться, что такое класс. Это что-то вроде шаблона, который является образцом для создания объектов. А ими, в свою очередь, является все. Чтобы создать объект, необходимо использовать оператор class. Имя непосредственно следует за ним, а потом ставится знак двоеточия. Давайте посмотрим на примере, как эта задача реализуется в реальных условиях.   

class ClassName:

   """Необязательная строка документации класса"""  

   class_suite
  • Класс включает так называемую строку документации. Чтобы работать с ней, можно воспользоваться ClassName.__doc__,
  • class_suite включает части класса, атрибуты и функции. 

Каким же образом на практике осуществляется создание класса? Вот так, как указано в этом коде: 

class Employee:  

    """Базовый класс для всех сотрудников"""  

    emp_count = 0  

  

    def __init__(self, name, salary):  

        self.name = name  

        self.salary = salary  

        Employee.emp_count += 1  

  

    def display_count(self):  

        print('Всего сотрудников: %d' % Employee.empCount)  

  

    def display_employee(self):  

        print('Имя: {}. Зарплата: {}'.format(self.name, self.salary))

Давайте разберем теперь этот код.

  1. emp_count – на этом месте стоит переменная класса, содержимое которой распределяется между его объектами. Доступ к ней возможен через Employee.emp_count как непосредственно из класса, так и в каком-угодно ином месте кода.
  2. 1-й метод – __init__() – это особая функция, еще называемая конструктором. Он вызывается Python в ходе генерации нового объекта, который создается по шаблону, заложенному в классе.
  3. Другие методы объявляются образом, аналогичным стандартным функциям. Единственное, первый аргумент для всех подобных методов – self. Он автоматически добавляется в список, и после этого нет необходимости выполнять его активацию в ходе вызова этих функций (то есть, методов).

Что нужно делать для правильного создания объектов класса?

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

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

# Это сгенерирует первый элемент Employee  

emp1 = Employee("Андрей", 2000)  

# Это сгененирует второй элемент Employee  

emp2 = Employee("Мария", 5000)

Атрибуты: как с ними работать?

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

emp1.display_employee()  

emp2.display_employee()  

print("Всего сотрудников: %d" % Employee.emp_count)

А теперь давайте все то, что мы ранее изучили, систематизируем в виде такого фрагмента кода. 

class Employee:  

    """Базовый класс для всех сотрудников"""  

    emp_count = 0  

  

    def __init__(self, name, salary):  

        self.name = name  

        self.salary = salary  

        Employee.emp_count += 1  

  

    def display_count(self):  

        print('Всего сотрудников: %d' % Employee.emp_count)

        

    def display_employee(self):  

        print('Имя: {}. Зарплата: {}'.format(self.name, self.salary))  

 

# Это создаст первый объект класса Employee  

emp1 = Employee("Андрей", 2000)  

# Это создаст второй объект класса Employee  

emp2 = Employee("Мария", 5000)  

emp1.display_employee()  

emp2.display_employee()  

print("Всего сотрудников: %d" % Employee.emp_count)

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

Имя: Андрей. Зарплата: 2000

Имя: Мария. Зарплата: 5000

Всего сотрудников: 2

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

emp1.age = 7  # Добавит атрибут 'age'

emp1.age = 8  # Изменит атрибут 'age'

del emp1.age  # Удалит атрибут 'age'

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

  • getattr(obj, name [, default]). Она позволяет получать доступ к атрибуту объекта. 
  • hasattr(obj, name) — проверяет, есть ли в obj атрибут name.
  • setattr(obj, name, value) — задает атрибут. Он будет сгенерирован автоматически, если окажется, что его не существует в списке тех, которые есть в наличии.
  • delattr(obj, name) — полностью убрать атрибут из списка тех, которые существуют в данный момент в приложении.
hasattr(emp1, 'age')  # возвращает true если атрибут 'age' существует

getattr(emp1, 'age')  # возвращает значение атрибута 'age' 

setattr(emp1, 'age', 8)  #устанавливает атрибут 'age' на 8

delattr(empl, 'age')  # удаляет атрибут 'age'

Встроенные атрибуты класса

Все описанное выше – это хорошо. Но что делать, если нам надо получить доступ к атрибутам, которые являются встроенными? В этом случае надо использовать тот же самый оператор, как и для всех остальных. Все классы в Python обладают определенным набором встроенных атрибутов. Давайте приведем их перечень.

  • __dict__ — этот атрибут являет собой словарь, в котором есть набор имен класса приложения.
  • __doc__ — это, как вы могли догадаться из приведенных выше примеров, строка документации класса. Поскольку этот атрибут необязательный, то он может отсутствовать. В этом случае используется None.
  • __name__ — имя класса.
  • __module__ — название модуля, в каком осуществляется определение класса. Это атрибут __main__ в интерактивном режиме.
  • __bases__ — они могут быть пустыми tuple, включающие классы, являющиеся базовыми, в порядке их появления в списке базового класса.

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

class Employee:  

    """Базовый класс для всех сотрудников"""  

    emp_count = 0  

  

    def __init__(self, name, salary):  

        self.name = name  

        self.salary = salary  

        Employee.empCount += 1  

  

    def display_count(self):  

        print('Всего сотрудников: %d' % Employee.empCount)  

  

    def display_employee(self):  

        print('Имя: {}. Зарплата: {}'.format(self.name, self.salary))  

  

print("Employee.__doc__:", Employee.__doc__)  

print("Employee.__name__:", Employee.__name__)  

print("Employee.__module__:", Employee.__module__)  

print("Employee.__bases__:", Employee.__bases__)  

print("Employee.__dict__:", Employee.__dict__)

В процессе выполнения этого кода будет получен следующий результат. 

Employee.__doc__: Базовый класс для всех сотрудников

Employee.__name__: Employee

Employee.__module__: __main__

Employee.__bases__: (<class 'object'>,)

Employee.__dict__: {'__module__': '__main__', '__doc__': 'Базовый класс для всех сотрудников', 'emp_count': 0, '__init__': <function Employee.__init__ at 0x03C7D7C8>, 'display_count': <function Employee.display_count at 0x03FA6AE0>, 'display_employee': <function Employee.display_employee at 0x03FA6B28>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>}

Как произвольно убирать элементы класса?

Ненужные объекты, в целом, убираются Python без дополнительного вмешательства разработчика приложения. Речь идет об объектах или встроенных типах, создаваемых на основе классов как существующих ранее, так и нет. Это делается, чтобы появилось больше свободного пространства в памяти. С использованием ‘Garbage Collection’ Python время от времени выполняет эту операцию.

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

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

a = 40  # создали объект <40>

b = a  # увеличивает количество ссылок  <40> 

c = [b]  # увеличивает количество ссылок <40> 




del a  # уменьшает количество ссылок <40>

b = 100  # уменьшает количество ссылок <40> 

c[0] = -1  # уменьшает количество ссылок <40>

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

Принцип работы деструктора

Давайте теперь приведем пример использования деструктора __del__(), который перед уничтожением вызывает имя класса. 

class Point:  

    def __init__(self, x=0, y=0):  

        self.x = x  

        self.y = y  

  

    def __del__(self):  

        class_name = self.__class__.__name__  

        print('{} уничтожен'.format(class_name))  

  

pt1 = Point()  

pt2 = pt1  

pt3 = pt1  

print(id(pt1), id(pt2), id(pt3))  # выведите id объектов  

del pt1  

del pt2  

del pt3

Вывод при выполнении вышеприведенного кода будет следующим.

17692784 17692784 17692784

Point уничтожен

Вообще, классы должны создаваться в специально отведенном для этого модуле, после чего импортироваться с использованием import SomeClass.

Что такое наследование?

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

Наследование класса: синтаксис

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

class SubClassName(ParentClass1[, ParentClass2, ...]):

"""Необязательная строка документации класса""" 

class_suite

Переопределение классов

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

class Parent:  # объявите родительский класс  

    def my_method(self):  

        print('Вызов родительского метода')  

   

class Child(Parent):  # объявите класс наследник  

    def my_method(self):  

        print('Вызов метода наследника')  

  

c = Child()  # экземпляр класса Child  

c.my_method()  # метод переопределен классом наследником

Выводы

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

ОфисГуру
Adblock
detector