Appearance
Class parameter self - Значение параметра self
В методах класса self — это ссылка на текущий экземпляр объекта. Благодаря ему у каждого экземпляра появляется собственное пространство для хранения атрибутов и доступа к методам класса.
Кто такой self?
- Внутри любого метода экземпляра первым параметром всегда идёт
self. - По соглашению его называют именно так, но технически это просто имя переменной.
self видимость атрибутов вне класса
self определяет видимость объявленных свойств экземпляра класса, делая их доступными через объект.
python
class ClassProperty:
property_class = "Class property"
def __init__(self, text: str = "default"):
self.property_instance_visible = f"Instance property. {text = }"
property_instance_hidden = f"Hidden local property. {text = }"
self.total = f"Total: {self.property_instance_visible = }, {property_instance_hidden = }, {text = }"
instance = ClassProperty()
print(f"{instance = }")
print(f"{instance.__dict__ = }")
print(f"{instance.__dir__() = }")
print(f"{instance.property_class = }")
print(f"{instance.property_instance_visible = }")
print(f"{instance.property_instance_hidden = }") # error
print(f"{instance.total = }")Пояснение работы кода
property_class— это свойство класса. Оно хранится в пространстве имён самого класса и доступно всем экземплярам.- Внутри
__init__создаются свойства экземпляраself.property_instance_visibleиself.total. - Локальная переменная
property_instance_hiddenживёт только во время выполнения конструктора и не сохраняется. instance.__dict__показывает все свойства, объявленные черезself.instance.__dir__()показывает атрибуты экземпляра и методы/свойства класса.- Доступ к
instance.property_classиinstance.property_instance_visibleработает без ошибок. - При попытке
instance.property_instance_hiddenвозникнет ошибкаAttributeError. - Итоговое свойство
totalсодержит в себе и видимые, и скрытые значения, но при этом скрытую часть он захвати и сохранил в строке.
Вывод в консоль:
instance = <__main__.ClassProperty object at 0x0000022765937CB0>
instance.__dict__ = {'property_instance_visible': "Instance property. text = 'default'", 'total': 'Total: self.property_instance_visible = "Instance property. text = \'default\'", property_instance_hidden = "Hidden local property. text = \'default\'", text = \'default\''}
instance.__dir__() = ['property_instance_visible', 'total', '__module__', '__firstlineno__', 'property_class', '__init__', '__static_attributes__', '__dict__', '__weakref__', '__doc__', '__new__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__reduce_ex__', '__reduce__', '__getstate__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
instance.property_class = 'Class property'
instance.property_instance_visible = "Instance property. text = 'default'"
instance.total = 'Total: self.property_instance_visible = "Instance property. text = \'default\'", property_instance_hidden = "Hidden local property. text = \'default\'", text = \'default\''Создание свойств в нескольких методах
В Python можно динамически добавлять атрибуты в любом методе, но это может привести к непредсказуемому поведению.
python
class ClassProperty:
property_class = "Class property"
def __init__(self):
property_local_init = "Hidden local property"
self.property_visible_init = "Visible instance property"
def any_method(self):
property_local_any = "Hidden local property"
self.property_visible_any = "Visible instance property" # warning
instance = ClassProperty()
print(f"{instance = }")
print(f"{instance.__dict__ = }")
print(f"{instance.__dir__() = }")
print(f"{instance.property_class = }")
print(f"{instance.property_visible_init = }")
# print(f"{instance.property_visible_any = }") # error
instance.any_method()
print(f"{instance.property_visible_any = }")
# print(f"{instance.property_local_init = }") # error
# print(f"{instance.property_local_any = }") # errorПояснение работы кода с учётом warning и errors
- После
instance = ClassProperty()в__init__создаётся толькоself.property_visible_init. - Словарь
instance.__dict__содержит один ключ:property_visible_init. - Пометка
# warningуказывает на потенциальную проблему: динамическое добавление атрибутов вне конструктора может запутать логику, если методы называются не в том порядке. - Метод
any_methodне вызывался, поэтомуself.property_visible_anyне появился, и попытка к нему обратиться также приведёт к ошибке (если метод не был вызван). - Вызов метода
instance.any_method()- инициализирует свойствоself.property_visible_any, поэтому в дальнейшем свойство доступно для работы. - Локальные переменные методов скрыты и никак не влияют на состояние экземпляра.
Вывод в консоль:
instance = <__main__.ClassProperty object at 0x0000026854FC7CB0>
instance.__dict__ = {'property_visible_init': 'Visible instance property'}
instance.__dir__() = ['property_visible_init', '__module__', '__firstlineno__', 'property_class', '__init__', 'any_method', '__static_attributes__', '__dict__', '__weakref__', '__doc__', '__new__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__reduce_ex__', '__reduce__', '__getstate__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
instance.property_class = 'Class property'
instance.property_visible_init = 'Visible instance property'
instance.property_visible_any = 'Visible instance property'self обращение к атрибутам внутри класса
С помощью self методы класса могут читать и менять состояние свойств экземпляра внутри класса.
python
class ClassProperty:
def __init__(self):
property_local_init = "Hidden local property"
self.property_visible_init = "Visible instance property"
self.total = f"{self.property_visible_init} {property_local_init}"
def any_method(self):
property_local_any = "Hidden local property"
self.property_visible_any = "Visible instance property" # warning
self.total = f"{self.property_visible_init} {self.property_visible_any} {property_local_any}"
instance = ClassProperty()
print(f"{instance = }")
print(f"{instance.__dict__ = }")
print(f"{instance.__dir__() = }")
print(f"{instance.total = }")
instance.any_method()
print(f"{instance.total = }")Пояснение работы кода
- После конструктора в
instance.__dict__есть два ключа:property_visible_initиtotal, гдеtotalотражает комбинацию видимого и локального значения. - До вызова
any_methodатрибутproperty_visible_anyотсутствует, поэтомуtotalпоказывает только свойство из__init__. - Внутри
any_methodсоздаётсяself.property_visible_anyи обновляетсяself.total, объединяя три фрагмента. - При каждом вызове метода состояние экземпляра изменяется, и новые значения доступны извне через
instance.total.
Вывод в консоль
instance = <__main__.ClassProperty object at 0x000001B37ADE7CB0>
instance.__dict__ = {'property_visible_init': 'Visible instance property', 'total': 'Visible instance property Hidden local property'}
instance.__dir__() = ['property_visible_init', 'total', '__module__', '__firstlineno__', '__init__', 'any_method', '__static_attributes__', '__dict__', '__weakref__', '__doc__', '__new__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__reduce_ex__', '__reduce__', '__getstate__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
instance.total = 'Visible instance property Hidden local property'
instance.total = 'Visible instance property Visible instance property Hidden local property'self вызов методов внутри класса
self не только управляет атрибутами, но и позволяет вызывать методы внутри класса. Вне класса как можно заметить методы вызываются через точку ..
python
class ClassProperty:
def __init__(self):
property_local_init = "Hidden local property"
self.property_visible_init = "Visible instance property"
self.total = f"{self.property_visible_init} {property_local_init}"
self.print_method("__init__")
def do_method(self):
property_local_any = "Hidden local property"
self.property_visible_any = "Visible instance property" # warning
self.total = f"{self.property_visible_init} {self.property_visible_any} {property_local_any}"
self.print_method("do_method")
def print_method(self, text: str):
print(f"This method call from {text}")
print(f"{self.total = }")
instance = ClassProperty()
print(f"{instance = }")
print(f"{instance.__dict__ = }")
print(f"{instance.__dir__() = }")
print(f"{instance.total = }")
instance.do_method()
print(f"{instance.total = }")
instance.print_method("print_method")Пояснение выполнения кода
- В конструкторе после установки атрибутов мгновенно вызывается
self.print_method("__init__"), поэтому в консоли появляется первая пара строк. print_methodполучает доступ кself.totalи выводит текущее значение.- При вызове
instance.do_method()внутри метода вновь обновляетсяtotal, затем снова вызываетсяprint_method. - Повторный
instance.print_method("print_method")демонстрирует, что методы могут вызываться извне с разными параметрами, работая с тем жеself.total. - Такая схема помогает вызывать вспомогательные методы без повторного дублирования кода.
Вывод в консоль:
This method call from __init__
self.total = 'Visible instance property Hidden local property'
instance = <__main__.ClassProperty object at 0x0000012BBF297E00>
instance.__dict__ = {'property_visible_init': 'Visible instance property', 'total': 'Visible instance property Hidden local property'}
instance.__dir__() = ['property_visible_init', 'total', '__module__', '__firstlineno__', '__init__', 'do_method', 'print_method', '__static_attributes__', '__dict__', '__weakref__', '__doc__', '__new__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__reduce_ex__', '__reduce__', '__getstate__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
instance.total = 'Visible instance property Hidden local property'
This method call from do_method
self.total = 'Visible instance property Visible instance property Hidden local property'
instance.total = 'Visible instance property Visible instance property Hidden local property'
This method call from print_method
self.total = 'Visible instance property Visible instance property Hidden local property'Локальные переменные vs свойства экземпляра
Персистентность — это продолжительность жизни переменной или атрибута, то есть время, в течение которого оно хранится и остаётся доступным:
- Локальная переменная живёт только внутри одного вызова метода (временная).
- Атрибут
self.xсохраняется вinstance.__dict__до момента удаления экземпляра (долговременная на время жизни объекта). - Свойство класса хранится в пространстве имён самого класса и существует ровно до момента выгрузки класса (едино для всех экземпляров).
| Тип переменной | Живёт в | Доступ извне | Персистентность |
|---|---|---|---|
Локальная (x = ...) | Внутри метода | Нет | Временная |
Через self.x = ... | instance.__dict__ | Да (instance.x) | Долговременная |
| Свойство класса | Внутри класса | Да (instance.prop) | Одна на класс |
self - итог
self - можно воспринимать как определение глобальности переменных и функций внутри класса. self можно воспринимать как пространство имён экземпляра. Он делает переменные и методы доступными в рамках одного объекта и отделяет данные разных экземпляров друг от друга.
Дополнительные замечания:
- Всегда объявляйте основные атрибуты экземпляра в
__init__, чтобы не запутывать пользователей класса. - Придерживайтесь соглашения именования: не меняйте
selfна что-то другое, чтобы код оставался понятным.
Упражнения
Создайте класс
Personс атрибутамиnameиage. Добавьте методbirthday, который увеличиваетageна 1, и сразу же вызывает методgreet, выводящий «Happy 25th birthday, Bob!».Напишите класс
Counter, в котором:- В конструкторе храните начальное значение счётчика используя
IntVar. - Метод
incrementувеличивает счётчик на заданное число. - Метод
decrementуменьшает счётчик. - Метод
resetсбрасывает значение счётчика на ноль.
Реализуйте оконное представление программы.
- В конструкторе храните начальное значение счётчика используя
Создайте класс проверки строки как числа с методами проверки:
- целое положительное число,
- целое отрицательное число,
- целое число,
- дробное положительное число,
- дробное отрицательное число,
- дробное число,
- положительное число,
- отрицательное число,
- число,
- число ноль.
Постарайтесь переиспользовать методы, в решении задания. Проверьте верность работы методов. Используйте данный класс проверки строки как числа для решения калькулятора полей.
Создайте класс Товар -
Goodс атрибутами: название, цена за единицу, количество, дней на использование товара.И методами проверки строки для калькулятора котенка:
- проверка название товара: не менее двух символов (минимум одной буквы с одно цифрой или буквы),
- проверка количества товара: целое положительное число, не ноль,
- проверка цены товара: положительное число, не более двух знаков после запятой,
- проверка дня: целое положительное число, не ноль,
- проверка года: целое или половинное число, не ноль.
Используйте класс в решении программы калькулятора котенка.