Первый экземпляр (переменная green) класса MyClass создается командой green=MyClass("Зеленый"). Для этого экземпляра поле nickname, очевидно, получает значение "Зеленый". При вызове конструктора в окне вывода отображаются сообщения с текстом "Создан экземпляр класса." и "Значение поля: Зеленый". Сразу после создания экземпляра green следует команда print(" Принадлежность : " , green.name ) . В ней обращение (инструкция green.name) к полю name объекта класса MyClass выполняется через экземпляр класса. В результате появляется сообщение с текстом "Принадлежность: Класс MyClass". Таким образом, значением инструкции green.name является текст "Класс MyClass" – то есть это значение поля name класса MyClass. Если бы мы вместо инструкции green.name использовали MyClass.name, получили бы точно такой же результат. В данной конкретной ситуации инструкции green.name и MyClass.name эквиваленты с точки зрения результата (но это не означает, что так будет всегда).
Второй экземпляр (переменная red) класса MyClass создается командой red=MyClass("Красный"). Поле nickname экземпляра red получает значение "Красный ". При вызове конструктора в окне вывода отображается текст " Создан экземпляр класса." и "Значение поля: Красный". При обращении к полю name класса MyClass через экземпляр класса в команде print("Принадлежность: ", red.name) результатом инструкции red.name будет текстовое значение поля name класса MyClass, о чем свидетельствует сообщение Принадлежность : Класс MyClass в окне вывода.
Может показаться, что поле класса – это всего лишь общее поле для всех экземпляров класса. Но тогда возникает вопрос: а что будет, если мы попытаемся изменить поле класса, присвоив ему значение не через ссылку на объект класса (например, MyClass.name), а через ссылку на экземпляр класса (например, green.name или red.name)? По логике можно ожидать, что изменения "почувствуют" все экземпляры класса. Но это не так. Рассмотрим программный код в листинге:
# Создаем класс class MyClass:
#Поле name класса name= " Kлacc MyClass"
#Метод для присваивания значения
#полю nickname экземпляра класса def set(self , n) :
self.nickname=n
#Метод для отображения значения
#поля nickname экземпляра класса def get(self) :
print("Значение пoля : " , self.nickname )
#Конструктор
def __init__(self, n) :
#Присваивается значение полю
50
#nickname экземпляра класса self.set (n)
#Отображается сообщение
print( "Coздaн экземпляр класса . " )
#Отображается значение поля
#nickname экземпляра класса self.get()
#Первый экземпляр (переменная green) green=MyClass("Зeлeный")
#Проверяем значение поля name
#через экземпляр green
рrint("Принадлежность : " , grееn.nаmе )
#Второй экземпляр переменная red) red=MyClass( " Kpacный " )
#Проверяем значение поля name
#через экземпляр red
рrint("Принадлежность : " , red.name )
#Изменяем значение поля name
#через экземпляр green
green.nаmе=" Здесь был Зеленый" ·
#Проверяем значение поля name
#через экземпляр red
рrint("Спрашивает Kpacный : " , red.name )
#Проверяем значение поля name
#через экземпляр green
рrint (" Спрашивает Зеленый : " , grееn.nаmе )
#Изменяем значение поля name
#через объект класса MyClass
MyClass.name = " Здecь могла быть Ваша реклама! "
#Проверяем значение поля name '
#через экземпляр red
рrint ( " Спрашивает Kpacный : " , red.name )
#Проверяем значение поля name
#через экземпляр green
рrint ("Спрашивает Зеленый: ", grееn . nаmе )
#Удаляем поле name э кземпляра green del (green.name)
#Проверяем значение поля name
#через экземпляр green
рrint ( " Спрашивает Зеленый : " , grееn . nаmе )
Поле объекта класса и поле экземпляра класса
Результат выполнения этого программного кода приведен ниже:
Создан экземпляр класса. Значение поля: Зеленый
Принадлежность: Класс Myclass Создан экземпляр класса .
51
Значение поля : Красный
Принадлежность : Класс MyClass Спрашивает Красный : Класс MyClass Спрашивает Зеленый : Здесь был Зеленый
Спрашивает Красный : Здесь могла быть Ваша реклама! Спрашивает Зеленый : здесь был Зеленый
Спрашивает Зеленый : Здесь могла быть Ваша реклама!
Ранее мы с помощью инструкции green.name считывали значение поля name, поэтому имеем некоторые основания рассчитывать на успех. Однако при выполнении команды print("Спрашивает Красный:", red.name) получаем в окне вывода сообщение Спрашивает Красный : Класс MyClass. То есть значение поля name, полученное по ссылке через экземпляр red не изменилось. Хотя при выполнении команды print ("Спрашивает Зеленый:" , green.name ) в окне вывода получаем вполне ожидаемое сообщение Спрашивает Зеленый: Здесь был Зеленый. Поворот событий достаточно неожиданный: пока мы через инструкцию green.name значение полю name не присваивали, значения выражений green.name и red.name совпадали, но после присваивания значения полю эти инструкции возвращают разные значения. Объяснение такое. При выполнении команды green.nаmе= "Здесь был Зеленый" на самом деле значение полю name класса MyClass не присваивается. Вместо этого создается поле с названием nare у экземпляра green, и этому полю присваивается значение "Здесь был Зеленый". И после этого каждый раз, когда мы будем использовать инструкцию green.name, она будет означать не поле name класса MyClass, а поле nare экземпляра green. Другими словами, поле name экземпляра green "перекрывает" поле nare класса MyClass. Но это только для экземпляра green. У экземпляра red поля name нет, поэтому инструкция red.name при считывании значения означает поле name класса MyClass.
При выполнении команды MyClass.nаmе= " Здесь могла быть Ваша реклама!" изменяется значение поля name класса MyClass. Поэтому когда в команде print ("Спрашивает Красный: ", red.name) используется ссылка red.name, то результатом этой инструкции будет новое значение поля name класса MyClass. А значение инструкции green.name в команде print ("Спрашивает Зеленый: " , green . name ) - это значение " Здесь был Зеленый " поля name экземпляра green.
На следующем этапе командой del(green.name) у экземпляра green удаляется поле name. После этого у экземпляра green поля name уже нет, и значением инструкции green.name в команде print("Спрашивает Зеленый : " , green.name ) является значение поля name класса MyClass.
После наших смелых экспериментов с полями объекта класса и экземпляров класса не сложно догадать, что поля можно добавлять и удалять,
52
причем это справедливо как для объекта класса, так и для экземпляров класса. Здесь мы обсудим и проанализируем две позиции:
Поля экземпляра класса можно добавлять и удалять после создания экземпляра класса.
Поля объекта класса можно добавлять и удалять после создания объекта класса.
С прикладной точки зрения ситуация в общем и целом несложная: для добавления поля экземпляра класса этому полю присваивается значение (разумеется, через ссылку на экземпляр класса). Примерно то же самое происходит при добавлении поля объекту класса: такому полю присваивается значение, и этого достаточно, чтобы у объекта класса появилось новое поле. Чтобы удалить поле у объекта класса, после оператора del указываем ссылку на поле объекта класса (в "точечном" формате: класс и, через точку, имя поля). Аналогичным образом удаляется и Поле экземпляра класса, только теперь после оператора del указывается ссылка на поле экземпляра класса (экземпляр класса, точки и имя поля).
Небольшой пример манипулирования с полями объекта класса и полями экземпляров класса приведен в листинге:
#Создаем класс class MyClass:
pass
#Создаем экземпляр А
A=MyClass()
#Создаем экземпляр В
B=MyClass()
#Экземпляру А добавляем
#поле first
А.first =" Экземпляр А "
#Экземпляру В добавляем
#поле seccond
В.second = " Экземпляр В "
#Классу MyClass добавляем
#поле total
MyClass.total= "Kлacc MyClass"
#Проверяем доступ к полям total и
#first через ссылку на экземпляр А print(А.total , " " , A.first )
#Проверяем доступ к полю second
#через ссылку на экземпляр А
try :
# Если Поле second есть print ( А.second )
# Ecли такого поля нет except AttributeError:
print ( "Taкoгo поля у экземпляра А нет ! " )
# Проверяем доступ к полям total и
53
# second через ссылку на экземпляр В print ( B.total, " " , B.second)
#Проверяем доступ к полю first
#через ссылку н а экземпляр В try:
#Если поле first есть
print(В.first )
#Если такого поля нет except AttributeError:
print ( " Taкoгo поля у экземпляра В нет ! " )
#Удаляем поле total класса MyClass del(MyClass.total)
#Проверяем доступ к полю total
#через ссылку на экземпляр А
try :
#Если поле есть print(A.total )
# Если поля нет except AttributeError:
print ( " Taкoгo поля нет ! " )
#Проверяем доступ к полю total
#через ссылку на экземпляр В try :
#Если поле есть
print (B.total)
#Если поля нет except AttributeError :
print ("Taкoгo поля нет!")
#Удаляем поле first экземпляра А del(A.first)
#Проверяем доступ к полю first
#через ссылку на экземпляр А try:
#Если поле есть
print (A.first)
# Если поля нет except AttributeError:
print ("Taкoгo поля у экземпляра А нет !")
Добавление и удаление полей
Результат выполнения программного кода такой:
Класс MyClass Экземпляр A
Такого поля у экземпляра А нет Класс MyClass Экземпляр B Такого поля у экземпляра в B нет
Такого поля нет! Такого поля нет!
54