Конструктор класса – метод __init__()

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

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

При этом методы перегрузки операторов не надо вызывать по имени. Вызовом для них является сам факт участия объекта в определенной операции. В случае конструктора класса – это операция создания объекта. Так как объект создается в момент вызова класса по имени, то в этот момент вызывается метод __init__(), если он определен в классе.

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

class Person:
    def setName(self, n, s):
        self.name = n
        self.surname = s

то создание объекта возможно без полей. Для установки имени и фамилии метод setName() нужно вызывать отдельно:

>>> from test import Person 
>>> p1 = Person()
>>> p1.setName("Bill", "Ross")
>>> p1.name, p1.surname
('Bill', 'Ross')

В свою очередь, конструктор класса не позволит создать объект без обязательных полей:

class Person:
    def __init__(self, n, s):
        self.name = n
        self.surname = s
 
p1 = Person("Sam", "Baker")
print(p1.name, p1.surname)

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

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

>>> p1 = Person()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() missing 2 required positional arguments: 'n' and 's'

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

class Rectangle:
    def __init__(self, w = 0.5, h = 1):
        self.width = w
        self.height = h
    def square(self):
        return self.width * self.height
 
rec1 = Rectangle(5, 2)
rec2 = Rectangle()
rec3 = Rectangle(3)
rec4 = Rectangle(h = 4)
print(rec1.square())
print(rec2.square())
print(rec3.square())
print(rec4.square())

Вывод:

10
0.5
3
2.0

Если класс вызывается без значений в скобках, то для параметров будут использованы их значения по умолчанию. Однако поля width и height будут у всех объектов.

 

 

Кроме того, конструктору вовсе не обязательно принимать какие-либо параметры, не считая self. Значения полям могут назначаться как угодно. Также не обязательно, чтобы в конструкторе происходила установка атрибутов объекта. Там может быть, например, код, который порождает создание объектов других классов.

Практическая работа. Конструктор и деструктор

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

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

В классах Python функцию деструктора выполняет метод __del__().

Напишите программу по следующему описанию:

  1. Есть класс Person, конструктор которого принимает три параметра (не учитывая self) – имя, фамилию и квалификацию специалиста. Квалификация имеет значение заданное по умолчанию, равное единице.

  2. У класса Person есть метод, который возвращает строку, включающую в себя всю информацию о сотруднике.

  3. Класс Person содержит деструктор, который выводит на экран фразу "До свидания, мистер …" (вместо троеточия должны выводиться имя и фамилия объекта).

  4. В основной ветке программы создайте три объекта класса Person. Посмотрите информацию о сотрудниках и увольте самое слабое звено.

  5. В конце программы добавьте функцию input(), чтобы скрипт не завершился сам, пока не будет нажат Enter. Иначе вы сразу увидите как удаляются все объекты при завершении работы программы.

В Python деструктор используется редко, так как интерпретатор и без него хорошо убирает "мусор".

Курс с примерами решений практических работ: android-приложение, pdf-версия.

Создано

Обновлено

Комментарии

Ответ на от plustilino

Добрый день! Такое впечатление что у меня конструктор почему то не работает.
>>> class Rectangle:
	width = 0
	height = 0
	def square(self):
		return self.width*self.height
 
 
>>> rect = Rectangle()
>>> print(rect.width)
0
Автоматом перестали делаться отступы в блоках
>>> class Rectangle:
	  def __init__(self, width, height):
	  self.width = width
 
SyntaxError: expected an indented block
>>>
Получается ошибка,делаю рестарт shell, все равно нет отступов автоматом и ошибка та же. Закрываю Python 3.7.0 Shell отступы работают, но конструктор нет
>>> class Rectangle:
	def __init__(self, width, height):
		self.width = width
		self.height = height
		def square(self):
			return self.width*self.height
 
 
>>> r = Rectangle(100, 50)
>>> print(r.height)
50
>>> print(r.square())
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    print(r.square())
AttributeError: 'Rectangle' object has no attribute 'square'
>>> 
Метод square не виден в подсказке когда пишу print(r.....) и появляется эта ошибка
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    print(r.square())
AttributeError: 'Rectangle' object has no attribute 'square'
Подскажите может shell как то криво встал и как проверить есть эта библиотека модуль не знаю что в оболочке как проверить?

Ответ на от Олег

Шел и не будет делать отступы автоматом. 

Не надо класть метод в конструктор. Делают так:

>>> class Rectangle:
...     def __init__(self, width, height):
...             self.width = width
...             self.height = height
...     def square(self):
...             return self.width * self.height
... 
>>> r = Rectangle(100, 50)
>>> r.square()
5000

Или так:

>>> class Rectangle:
...     def __init__(self, width, height):
...             self.width = width
...             self.height = height
...             self.square = self.square()
...     def square(self):
...             return self.width * self.height
... 
>>> r = Rectangle(100, 50)
>>> r.square
5000

Ответ на от plustilino

>>> class Rectangle:
	def __init__(self, w, h):
		self.w = w
		self.h = h
		def square(self):
			return self.w * self.h
 
 
>>> r = Rectangle(100, 50)
>>> r.square()
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    r.square()
AttributeError: 'Rectangle' object has no attribute 'square'
>>> 
>>> class Rectangle:
	w = 100
	h = 50
	def square(self):
		return self.w * self.h
 
 
>>> r = Rectangle()
>>> r.square()
5000
>>> 

Ответ на от Олег

Разница в том, что у вас def square() на разных уровнях вложенности. В первом случае внутри __init__(), что неправильно. В теле конструктора размещают поля (переменные) и вызовы методов, но не определения методов.

Ответ на от plustilino

Большое спасибо!
Но если честно я разочарован питоном.
Такая мелочь как отступ лишний так сильно на все влияет.
Вложенность не пробелами или новой строкой должна определяться а символами понятными, а не как здесь __ поди догадайся что это 2 _
В php, html да где угодно хоть все в строчку пиши, и блочность чисто условная для удобства восприятия, а тут прямо догма:-(((((
Уже не помню как в Visual Basic было, но вроде там тоже на синтакисис не особо заморачивались, может я не прав конечно и это же ооп! Там всегда так:-((((
Вот беда то

Ответ на от Олег

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

class Person:
 
    def __init__(self, name, surname, position=1):
        self.name = name
        self.surname = surname
        self.position = position
 
    def display(self):
        return self.name, self.surname, self.position
 
    def __del__(self):
        print "Goodbye Mr. {} {}".format(self.name, self.surname)
 
p1 = Person('big', 'dude', 3)
print p1.display()
 
p2 = Person('small', 'croon', 4)
print p2.display()
 
p3 = Person('neutral', 'guy', 5)
print p3.display()
 
del p2
 
try:
    input("Press Enter and exit")
except SyntaxError:
    exit()

Спасибо, после вашей статьи понял тему про __init__ На остальных ресурсах менее понятно. Сенкс
print ("Спасибо за пост")

class Person:
    def __init__(self, name, lastname, qual=1):
        self.name = name
        self.lastname = lastname
        self.qual = qual
 
    def __repr__(self):
        return "" % (self.name, self.lastname, self.qual)
 
    def info(self):
        print(f"Сотрудник {self.name} {self.lastname} имеет квалификацию {self.qual}")
 
    def __del__(self):
        print(f"До свидания, мистер {self.name} {self.lastname}")
 
def byQual_key(person):
    return person.qual
 
persons = []
persons.append(Person("Иван", "Иванов", 2))
persons.append(Person("Петр", "Петров"))
persons.append(Person("Сидр", "Сидоров", 3))
 
p = sorted(persons, key = byQual_key, reverse=True)
 
for i in p:
    i.info()
 
p[-1].__del__()
 
print("Press ENTER to exit")
input()