Конструктор класса – метод __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. Значения полям могут назначаться как угодно. Также не обязательно, чтобы в конструкторе происходила установка атрибутов объекта. Там может быть, например, код, который порождает создание объектов других классов.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Комментарии

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()

Ответ на от Алексей

Для чего использовали i.info()

Ответ на от Нурлыбай

Фраза про увольнение появляется, но физически из списка он не удаляется. При проверке списка после увольнения, он отражается в сотрудниках.

В задании сказано, что квалификация задана в классе Person и равна 1. А потом говорится уволить самое слабое звено. Но они же все имеют квалификацию = 1. ? Зарание спасибо.

Подскажите советом, как правильней организовать список персонажей, что бы не ручками и глазками высматривать "самое слабое звено", а найти программно и его удалить? Решение задачи:
class person:
    def __init__(self, fName, lName, qual=1, gender='M'):
        self.fName=fName
        self.lName=lName
        self.qual=qual
        self.gender='Male' if gender=='M' else 'Female' if gender=='F' else 'WHO ARE YOU?'
 
    def __del__(self):
        return f'Goodbye {str(self)}'
 
    def __repr__(self):
        return f'{self.lName[0].upper()}{self.lName[1:]} {self.fName[0].upper()}'
 
    def getInfo(self):
        return f'Person: [{str(self)}]\n - Qualification: [{self.qual}]\n - Gender: [{self.gender}]'
 
anton=person('anton','ukupnik')
vasya=person('vasya','pupkin',qual=3)
anna=person('anna','ivanova',gender='F', qual=4)
 
print(anton.getInfo())
print(anna.getInfo())
print(vasya.getInfo())
 
print(anton.__del__())
 
input('press enter to exit')

Ответ на от plustilino

Класс дополнил методами: ...
    def __lt__(self, other):
        return self.qual < other.qual
 
    def __gt__(self, other):
        return self.qual > other.qual
...
pList=[person('anton','ukupnik'),
    person('igor','nikolaev'), 
    person('vasya','pupkin',qual=3),
    person('anna','ivanova',gender='F', qual=4)]
 
 
print('remove outsiders:')
for pers in list(filter(lambda x: x.qual==min(pList).qual, pList)):
    pList.remove(pers)
    print(pers.__del__())

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

#!/bin/env python36
class Person:
    def __init__(self, n, s, q = 1):
        self.name = n
        self.surname = s
        self.qualification = int(q)
    def getInfo(self):
       return  self.name, self.surname, self.qualification
    def __del__(self):
        print('Goodbye Mr.', self.name, self.surname)
 
one = Person('Ivan', 'Drago', 2)
two = Person('John', 'Smith', 12)
three = Person('Natalia', 'Lazareva', 3)
four = Person('Simon', 'Bull', 5)
print(one.getInfo())
print(two.getInfo())
print(three.getInfo())
print(four.getInfo())
skill_list = []
for skill in one.qualification, two.qualification, three.qualification, four.qualification:
    skill_list.append(skill)
weak = min(skill_list)
for per in one, two, three, four:
    if per.qualification == weak:
        per.__del__()
input()

А почему нельзя сделать нужные поля в Class A: , вместо __init__ ? Или при создании объекта учитывается только метод __init__, а указанные поля в самом классе не идут в использование(при создании объекта)?

class Person():
 
    def __init__(self, name, surname, kvala = 1):
        self.name = name
        self.surname = surname
        self.kvala = kvala
 
    def vozv(self):
        return self.name, self.surname, self.kvala
 
    def __del__(self):
        print ('Goodbye', self.name, self.surname)
 
Alba = Person("Alba", "Bakker", "13")
Samanta = Person("Samanta", "Bekker", "14")
Lila = Person("Lila", "Arhib", "33")
 
print (Alba.vozv(), Samanta.vozv(), Lila.vozv())
 
a = input()
#Вот что получилось
Есть несколько вопросов: 1) Можно ли как-то вывести все созданные объекты по данному классу, не чередуя их через запятую в print ? 2) Почему у меня после моего Input'а выводится "Goodbye name, surname" по всем трем объектам ?хотя даже команды нету 3) Не понял как использовать деструктор для удаления определенного объекта? Пример: Alba.__del__() - так ?

Ответ на от And

2) потому что при завершении программы удаляются все объекты автоматически, input() тут не причем.

3) можно удалять del Alba.

1) только если вы поместите объекты в список. Хотя возможно есть какой-то специфический вариант нахождения в программе всех объектов одного класса. Мне неизвестно.

Скачал на телефон PDF AByteOfPython. Книга сама по себе хороша, но в силу моего возраста и опыта слишком сложна. Выключил телефон. Открыл этот сайт и сразу всё понял!

import random
 
class Person:
 
    def __init__(self, name, surname, skill = 1):
        self.name = name
        self.surname = surname
        self.skill = skill
 
    def __del__(self):
        print(f"Farewell, Mr. {self}")
 
    def __str__(self):
        return f"{self.name} {self.surname}, skill: {self.skill}"
 
 
def fire_weakest(persons_list):
    min_skill = persons_list[0].skill
    for p in persons_list:
        if p.skill < min_skill:
            min_skill = p.skill
    weakest = filter(lambda person: person.skill == min_skill , persons_list)
    for p in weakest:
        persons_list.remove(p)
        del p
 
 
NAMES = ["Jonh", "Bob", "Tom", "Bob", "Bill", "Harry", "Sam", "Nick", "Dan"]
SURNAMES = ["Jonhson", "Smith", "Davis", "Taylor", "Wilson", "Evans", "Brown"]
PERSONS_NUMBER = 6
 
rnd = random.Random()
 
persons = []
 
for i in range(PERSONS_NUMBER):
    name = NAMES[rnd.randint(0,len(NAMES) - 1)]
    surname = SURNAMES[rnd.randint(0,len(SURNAMES) - 1)]
    skill = rnd.randint(1,10)
    persons.append(Person(name, surname, skill))
 
for p in persons:
    print(p)
 
print("\nFiring the weakest:")
 
fire_weakest(persons)
print("\nAfter weakest fired:")
for p in persons:
    print(p)
 
input()