Материал: Разработка программных пакетов на языке Python. учебное пособие. Амоа К.А., Рындин Н.А

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Первый экземпляр (переменная 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.

5.3. Добавление и удаление полей и методов

После наших смелых экспериментов с полями объекта класса и экземпляров класса не сложно догадать, что поля можно добавлять и удалять,

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

Источник: https://studfile.net/preview/16565614/