Б41 Чистый Python. Тонкости программирования для профи. Спб.: Питер



Download 6,94 Mb.
Pdf ko'rish
bet45/80
Sana24.02.2022
Hajmi6,94 Mb.
#212875
1   ...   41   42   43   44   45   46   47   48   ...   80
Bog'liq
978544610803 Chisty Python Tonko

Переменные класса объявляются внутри определения класса (но 
за пределами любых методов экземпляра). Они не привязаны ни к од-
ному конкретному экземпляру класса. Вместо этого переменные клас-
са хранят свое содержимое в самом классе, и все объекты, созданные 
на основе того или иного класса, предоставляют общий доступ к одина-
ковому набору переменных класса. Например, это означает, что моди-
фикация переменной класса одновременно затрагивает все экземпляры 
объекта.
Переменные экземпляра всегда привязаны к конкретному экземпляру 
объекта. Их содержимое хранится не в классе, а в каждом отдельном 
объекте, созданном на основе класса. По этой причине содержимое пере-
менной экземпляра абсолютно независимо от одного экземпляра объекта 


4 .7 . Переменные класса против переменных экземпляра: подводные камни 137
к другому. И поэтому модификация переменной экземпляра одновремен-
но затрагивает только один экземпляр объекта.
Ладно, все это было довольно абстрактно — самое время рассмотреть 
немного исходного кода! Давайте потренируемся на собачках… В обу-
чающих пособиях, посвященных ООП, для иллюстрации этого тезиса 
всегда используются автомобили или домашние животные, и мне сложно 
отказаться от этой традиции.
Что собаке для счастья нужно? Правильно! Четыре лапы да имя:
class Dog:
num_legs = 4 # <- Переменная класса
def __init__(self, name):
self.name = name # <- Переменная экземпляра
О’кей. У нас есть изящное объектно-ориентированное представление 
ситуации с собакой, которую я только что описал. Создание новых экзем-
пляров 
Dog
работает, как и ожидалось, и каждый из них получает пере-
менную экземпляра с именем 
name
:
>>> jack = Dog('Джек') 
>>> jill = Dog('Джилл') 
>>> jack.name, jill.name 
('Джек', 'Джилл') 
Во всем, что касается переменных класса, всегда есть чуть больше гибко-
сти. Доступ к переменной класса 
num_legs
можно получить либо непо-
средственно в каждом экземпляре 
Dog
, либо в самом классе:
>>> jack.num_legs, jill.num_legs 
(4, 4) 
>>> Dog.num_legs 

Однако попытка получить доступ к переменной экземпляра через класс 
потерпит неудачу с исключением 
AttributeError
. Переменные экземпля-
ра характерны для каждого экземпляра объекта и создаются, когда выпол-
няется конструктор 
__init__
— они даже не существуют в самом классе.


138 Глава 4 • Классы и ООП
В этом заключается ключевое различие между переменными класса 
и переменными экземпляра:
>>> Dog.name 
AttributeError:
"type object 'Dog' has no attribute 'name'"
Ладно, пока все идет неплохо.
Допустим, в один прекрасный день пес по кличке Джек поедал свой ужин, 
расположившись слишком близко от микроволновки, в результате у него 
выросла дополнительная пара лап. Как бы вы представили этот факт в не-
большой «песочнице» с исходным кодом, которая у нас сейчас есть?
Первая идея — просто модифицировать переменную 
num_legs
в классе 
Dog
:
>>> Dog.num_legs = 6
Но помните, мы не хотим, чтобы все собаки стали носиться вокруг о шести 
лапах. Итак, сейчас мы только что превратили каждую собаку в нашей ми-
кровселенной в сверхсобаку, потому что мы модифицировали переменную 
класса. Это затрагивает всех собак, даже тех, которые были созданы ранее:
>>> jack.num_legs, jill.num_legs 
(6, 6)
Этот вариант не сработал. А не сработал он потому, что модификация 
переменной класса в пространстве имен класса затрагивает все экзем-
пляры класса. Давайте отыграем это изменение в переменной класса 
назад и вместо этого попробуем дать дополнительную пару лап только 
конкретному псу Джеку:
>>> Dog.num_legs = 4 
>>> jack.num_legs = 6 
Так, и что за чудовище мы получили? Сейчас выясним:
>>> jack.num_legs, jill.num_legs, Dog.num_legs 
(6, 4, 4)


4 .7 . Переменные класса против переменных экземпляра: подводные камни 139
Ладно. Выглядит «довольно неплохо» (ну, кроме того, конечно, что мы 
прямо сейчас дали бедному псу несколько лишних лап). Но как это из-
менение на самом деле повлияло на наши объекты 
Dog
?
А проблема, как выясняется, здесь в следующем: несмотря на то что мы 
получили желаемый результат (лишние лапы для Джека), мы внесли 
переменную экземпляра 
num_legs
в экземпляр с псом по кличке Джек. 
И теперь новая переменная экземпляра 
num_legs
«оттеняет» переменную 
класса с тем же самым именем, переопределяя и скрывая ее, когда мы об-
ращаемся к области действия экземпляра:
>>> jack.num_legs, jack.__class__.num_legs 
(6, 4)
Как вы видите, переменные класса, казалось бы, стали несогласованными
Это произошло потому, что внесение изменения в 
jack.num_legs
созда-
ло переменную экземпляра с тем же самым именем, что и у переменной 
класса.
Это не всегда плохо, но важно понимать, что именно здесь произошло. 
Прежде чем я наконец-то разобрался в области действия уровня класса 
и уровня экземпляра в Python, это было широкими воротами, через кото-
рые в мои программы то и дело закрадывались ошибки.
Сказать по правде, попытка модифицировать переменную класса через 
экземпляр объекта, который затем непредумышленно создает переменную 
экземпляра с тем же именем, затеняя оригинальную переменную класса, 
является в Python чем-то вроде подводного камня ООП.
Пример без собак
Хотя в процессе написания этого раздела книги ни одна собака не по-
страдала (это все шутки и игры до тех пор, пока кто-то не вырастит себе 
лишнюю пару лап), я хочу дать вам еще один практический пример 
полезных штук, которые вы можете сделать с переменными класса. То, 
что будет немного ближе к реальным приложениям с переменными 
класса.


140 Глава 4 • Классы и ООП
Итак, вот этот пример. Приведенный ниже класс 
CountedObject
отсле-
живает, сколько раз он использовался для создания экземпляров на про-
тяжении жизни программы (что на деле может обеспечить интересный 
метрический показатель производительности):
class CountedObject:
num_instances = 0
def __init__(self):
self.__class__.num_instances += 1
Класс 
CountedObject
содержит переменную класса 
num_instances
, которая 
служит в качестве общего счетчика. Когда класс объявлен, он инициали-
зирует счетчик нулем, а затем оставляет его в покое.
Всякий раз, когда вы создаете новый экземпляр этого класса, он увели-
чивает общий счетчик на единицу во время выполнения конструктора 
__init__
:
>>> CountedObject.num_instances 

>>> CountedObject().num_instances 

>>> CountedObject().num_instances 

>>> CountedObject().num_instances 

>>> CountedObject.num_instances 
3
Обратите внимание, как этот фрагмент кода должен проскакивать через 
небольшой обруч, чтобы обеспечить увеличение переменной счетчика 

Download 6,94 Mb.

Do'stlaringiz bilan baham:
1   ...   41   42   43   44   45   46   47   48   ...   80




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish