На этом шаге мы рассмотрим доступ к атрибутам и методам класса, а также особенности сосздания атрибутов.
Для доступа к атрибутам и методам можно использовать и следующие функции:
getattr(<Объект>, <Атрибут>[, <Значение по умолчанию>])
Если указанный атрибут не найден, возбуждается исключение AttributeError. Чтобы избежать вывода сообщения об ошибке, можно в третьем параметре указать значение, которое будет возвращаться, если атрибут не существует;
setattr(<Объект>, <Атрибут>, <Значение>)
Вторым параметром метода setattr() можно передать имя несуществующего атрибута - в этом случае атрибут с указанным именем будет создан;
Продемонстрируем работу функций на следующем примере:
class MyClass: def __init__(self): self.x = 10 def get_x(self): return self.x c = MyClass() # Создаем экземпляр класса print(getattr(c, "x")) # Выведет: 10 print(getattr(c, "get_x" ) ()) # Выведет: 10 print(getattr(c, "y", 0)) # Выведет: 0, т. к. атрибут не найден setattr(c, "y", 20) # Создаем атрибут y print(getattr(c, "y", 0)) # Выведет: 20 delattr(c, "y") # Удаляем атрибут у print(getattr(c, "y", 0)) # Выведет: 0, т. к. атрибут не найден print(hasattr(c, "x") ) # Выведет: True print(hasattr(c, "y") ) # Выведет: False
Результат работы приложения:
10
10
0
20
0
True
False
Все атрибуты класса в языке Python являются открытыми (public), т. е. доступными для непосредственного изменения как из самого класса, так и из других классов и из основного кода программы.
Кроме того, атрибуты допускается создавать динамически после создания класса - можно создать как атрибут объекта класса, так и атрибут экземпляра класса. Рассмотрим это на следующем примере:
class MyClass: # Определяем пустой класс pass MyClass.x = 50 # Создаем атрибут объекта класса c1, c2 = MyClass(), MyClass() # Создаем два экземпляра класса c1.y = 10 # Создаем атрибут экземпляра класса c2.y = 20 # Создаем атрибут экземпляра класса print(c1.x, c1.y) # Выведет: 50 10 print(c2.x, c2.y) # Выведет: 50 20
Результат работы приложения:
50 10
50 20
В этом примере мы определяем пустой класс, разместив в нем оператор pass. Далее создаем атрибут объекта класса (х). Этот атрибут будет доступен всем создаваемым экземплярам класса. Затем создаем два экземпляра класса и добавляем одноименные атрибуты (y). Значения этих атрибутов будут разными в каждом экземпляре класса. Но если создать новый экземпляр (например, c3), то атрибут у в нем определен не будет. Таким образом, с помощью классов можно имитировать типы данных, поддерживаемые другими языками программирования (например, тип struct, доступный в языке С).
Очень важно понимать разницу между атрибутами объекта класса и атрибутами экземпляра класса. Атрибут объекта класса доступен всем экземплярам класса, но после изменения атрибута значение изменится во всех экземплярах класса. Атрибут экземпляра класса может хранить уникальное значение для каждого экземпляра, и изменение его в одном экземпляре класса не затронет значения одноименного атрибута в других экземплярах того же класса. Рассмотрим это на примере, создав класс с атрибутом объекта класса (х) и атрибутом экземпляра класса (у):
class MyClass: x = 10; # Атрибут экземпляра класса def __init__(self): self.y = 20 # Атрибут экземпляра класса c1 = MyClass() # Создаем экземпляр класса c2 = MyClass() # Создаем экземпляр класса print(c1.x, c2.x) # Выведет: 10 10 MyClass.x = 88 # Изменяем атрибут объекта класса print(c1.x, c2.x) # Выведет: 88 88 print(c1.y, c2.y) # Выведет: 20 20 c1.y = 88 # Изменяем атрибут экземпляра класса print(c1.y, c2.y) # Выведет: 88 20
Результат работы приложения:
10 10
88 88
20 20
88 20
Сначала создается класс MyClass, а затем два экземпляра этого класса:
c1 = MyClass() # Создаем экземпляр класса c2 = MyClass() # Создаем экземпляр класса
Выведем значения атрибута x, а затем изменим значение и опять произведем вывод:
print(c1.x, c2.x) # Выведет: 10 10 MyClass.x = 88 # Изменяем атрибут объекта класса print(c1.x, c2.x) # Выведет: 88 88
Как видно из примера, изменение атрибута объекта класса затронуло значение в двух экземплярах класса сразу. Теперь произведем аналогичную операцию с атрибутом y:
print(c1.y, c2.y) # Выведет: 20 20 c1.y = 88 # Изменяем атрибут экземпляра класса print(c1.y, c2.y) # Выведет: 88 20
В этом случае изменилось значение атрибута только в экземпляре c1.
Следует также учитывать, что в одном классе могут одновременно существовать атрибут объекта и атрибут экземпляра с одним именем. Изменение атрибута объекта класса мы производили следующим образом:
MyClass.x = 88 # Изменяем атрибут объекта класса
Если после этой инструкции вставить инструкцию
c1.x = 200 # Создаем атрибут экземпляра
print(c1.x, MyClass.x) # Выведет: 200 88
На следующем шаге мы рассмотрим методы __init()__ и __del()__.