Что такое атрибут класса
Перейти к содержимому

Что такое атрибут класса

  • автор:

Что такое атрибут класса

Кроме атрибутов объектов в классе можно определять атрибуты классов. Подобные атрибуты определяются в виде переменных уровня класса. Например:

class Person: type = "Person" description = "Describes a person" print(Person.type) # Person print(Person.description) # Describes a person Person.type = "Class Person" print(Person.type) # Class Person

Здесь в классе Person определено два атрибута: type, который хранит имя класса, и description, который хранит описание класса.

Для обращения к атрибутам класса мы можем использовать имя класса, например: Person.type , и, как и атрибуты объекта, мы можем получать и изменять их значения.

Подобные атрибуты являются общими для всех объектов класса:

class Person: type = "Person" def __init__(self, name): self.name = name tom = Person("Tom") bob = Person("Bob") print(tom.type) # Person print(bob.type) # Person # изменим атрибут класса Person.type = "Class Person" print(tom.type) # Class Person print(bob.type) # Class Person

Атрибуты класса могут применяться для таких ситуаций, когда нам надо определить некоторые общие данные для всех объектов. Например:

class Person: default_name = "Undefined" def __init__(self, name): if name: self.name = name else: self.name = Person.default_name tom = Person("Tom") bob = Person("") print(tom.name) # Tom print(bob.name) # Undefined

В данном случае атрибут default_name хранит имя по умолчанию. И если в конструктор передана пустая строка для имени, то атрибуту name передается значение атрибута класса default_name. Для обращения к атрибуту класса внутри методов можно применять имя класса

self.name = Person.default_name
Атрибут класса

Возможна ситуация, когда атрибут класса и атрибут объекта совпадает по имени. Если в коде для атрибута объекта не задано значение, то для него может применяться значение атрибута класса:

class Person: name = "Undefined" def print_name(self): print(self.name) tom = Person() bob = Person() tom.print_name() # Undefined bob.print_name() # Undefined bob.name = "Bob" bob.print_name() # Bob tom.print_name() # Undefined

Здесь метод print_name использует атрибут объект name, однако нигде в коде этот атрибут не устанавливается. Зато на уровне класса задан атрибут name. Поэтому при первом обращении к методу print_name, в нем будет использоваться значение атрибута класса:

tom = Person() bob = Person() tom.print_name() # Undefined bob.print_name() # Undefined

Однако далее мы можем поменять установить атрибут объекта:

bob.name = "Bob" bob.print_name() # Bob tom.print_name() # Undefined

Причем второй объект — tom продолжит использовать атрибут класса. И если мы изменим атрибут класса, соответственно значение tom.name тоже изменится:

tom = Person() bob = Person() tom.print_name() # Undefined bob.print_name() # Undefined Person.name = "Some Person" # меняем значение атрибута класса bob.name = "Bob" # устанавливаем атрибут объекта bob.print_name() # Bob tom.print_name() # Some Person

Статические методы

Кроме обычных методов класс может определять статические методы. Такие методы предваряются аннотацией @staticmethod и относятся в целом к классу. Статические методы обычно определяют поведение, которое не зависит от конкретного объекта:

class Person: __type = "Person" @staticmethod def print_type(): print(Person.__type) Person.print_type() # Person - обращение к статическому методу через имя класса tom = Person() tom.print_type() # Person - обращение к статическому методу через имя объекта

В данном случае в классе Person определен атрибут класса __type , который хранит значение, общее для всего класса — название класса. Причем поскольку название атрибута предваряется двумя подчеркиваниями, то данный атрибут будет приватным, что защитит от недопустимого изменения.

Также в классе Person определен статический метод print_type , который выводит на консоль значение атрибута __type. Действие этого метода не зависит от конкретного объекта и относится в целом ко всему классу — вне зависимости от объекта на консоль будет выводится одно и то же значение атрибута __type. Поэтому такой метод можно сделать статическим.

Атрибуты класса и переменные экземпляра класса в Python

Переменные экземпляра класса предназначены для данных, уникальных для каждого экземпляра класса, а переменные класса (атрибуты данных класса) — для атрибутов и методов, общих для всех экземпляров класса.

Python вызывает специальный метод __init__() , который называют конструктором класса, каждый раз при создании нового экземпляра класса.

class Dog: # атрибут данных (переменная класса), # общая для всех экземпляров класса kind = 'canine' def __init__(self, name): # переменная экземпляра класса # уникальна для каждого экземпляра self.name = name >>> d = Dog('Fido') >>> e = Dog('Buddy') # переменная `kind` будет общая для # всех экземпляров объекта `Dog` >>> d.kind # 'canine' >>> e.kind # 'canine' # переменная `name` будет уникальна # для каждого из экземпляров >>> d.name # 'Fido' >>> e.name # 'Buddy' 

Как говорилось в материале «Классы в языке Python», общие данные могут иметь неожиданный эффект при использовании изменяемых объектов, таких как списки и словари. Например, список tricks (трюки, которые может делать отдельная собака) в примере ниже не следует использовать как атрибут данных/переменную класса, потому что для всех экземпляров класса Dog будет использоваться только один атрибут данных tricks :

class Dog: # ошибочное использование атрибута tricks - # переменной класса tricks = [] def __init__(self, name): self.name = name def add_trick(self, trick): self.tricks.append(trick) >>> d = Dog('Fido') >>> e = Dog('Buddy') >>> d.add_trick('roll over') >>> e.add_trick('play dead') # неожиданно разделяется всеми собаками >>> d.tricks # ['roll over', 'play dead'] 

Правильный дизайн класса должен использовать tricks не как атрибут данных класса, а как переменную экземпляра класса:

class Dog: def __init__(self, name): self.name = name # создает новый пустой список # трюков для каждой собаки self.tricks = [] def add_trick(self, trick): self.tricks.append(trick) >>> d = Dog('Fido') >>> e = Dog('Buddy') >>> d.add_trick('roll over') >>> e.add_trick('play dead') >>> d.tricks # ['roll over'] >>> e.tricks # ['play dead'] 

Если одно и то же имя атрибута встречается как в экземпляре класса, так и в самом классе, то поиск атрибута определяет приоритет экземпляра класса:

>>> class Warehouse: purpose = 'storage' region = 'west' >>> w1 = Warehouse() >>> print(w1.purpose, w1.region) # storage west >>> w2 = Warehouse() >>> w2.region = 'east' >>> print(w2.purpose, w2.region) # storage east 

На атрибуты данных класса могут ссылаться как методы, так и обычные пользователи — «клиенты» объекта. Другими словами, классы не могут использоваться для реализации чисто абстрактных типов данных. Фактически, ничто в Python не позволяет принудительно скрывать данные — все основано на соглашении.

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

В Python нет сокращений для ссылки на атрибуты данных или другие методы изнутри методов. Это повышает удобочитаемость методов: нет возможности путать локальные переменные и переменные экземпляра при просмотре метода.

Вместо использования привычной точечной нотации для доступа к атрибутам можно использовать встроенные функции:

  • getattr(obj, name [, default]) — для доступа к атрибуту name объекта класса obj .
  • hasattr(obj, name) — проверить, есть ли в классе obj атрибут name .
  • setattr(obj, name, value) — задать атрибут name со значением value . Если атрибут не существует, он будет создан.
  • delattr(obj, name) — удалить атрибут name из объекта класса obj .
Встроенные атрибуты класса.

Классы Python хранят встроенные атрибуты, к которым можно получить доступ как к любому другому атрибуту данных.

  • __dict__ — словарь, содержащий пространство имен класса.
  • __doc__ — строка документации класса. None если, документация отсутствует.
  • __name__ — имя класса.
  • __module__ — имя модуля, в котором определяется класс.
  • __bases__ — кортеж, содержащий базовые классы, в порядке их появления. Кортеж будет пустым, если наследование не было.
  • __mro__ — Порядок разрешения методов в множественном наследовании.

Где хранятся атрибуты класса и экземпляра класса?

Python не был бы Python без четко определенного и настраиваемого поведения атрибутов. Атрибуты в Python хранятся в магическом методе с именем __dict__ . Получить доступ к нему можно следующим образом:

class MyClass: class_attr = "Class" def __init__(self): self.instance_attr = "Instance" >>> my_object = MyClass() # атрибут экземпляра класса >>> my_object.__dict__ # # атрибут экземпляра класса >>> MyClass.__dict__['class_attr'] # 'Class' >>> my_object.class_attr 'Class' >>> my_object.instance_attr 'Instance' 
  • ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
  • Пространство имен и область видимости в классах
  • Определение классов
  • Объект класса и конструктор класса
  • Создание экземпляра класса
  • Метод экземпляра класса
  • Что такое метод класса и зачем нужен
  • Что такое статический метод в классах Python и зачем нужен
  • Атрибуты класса и переменные экземпляра класса
  • Кэширование методов экземпляра декоратором lru_cache
  • Закрытые/приватные методы и переменные класса Python
  • Наследование классов
  • Множественное наследование классов
  • Абстрактные классы
  • Перегрузка методов в классе Python
  • Что такое миксины и как их использовать
  • Класс Python как структура данных, подобная языку C
  • Создание пользовательских типов данных
  • Специальные (магические) методы класса Python
  • Базовая настройка классов Python магическими методами
  • Настройка доступа к атрибутам класса Python
  • Дескриптор класса для чайников
  • Протокол дескриптора класса
  • Практический пример дескриптора
  • Использование метода .__new__() в классах Python
  • Специальный атрибут __slots__ класса Python
  • Специальный метод __init_subclass__ класса Python
  • Определение метаклассов metaclass
  • Эмуляция контейнерных типов в классах Python
  • Другие специальные методы класса
  • Как Python ищет специальные методы в классах
  • Шаблон проектирования Фабрика и его реализация

Атрибут class

Атрибут class задает один или несколько классов для элемента (под элементом имеется ввиду тег).

Это делается для того, чтобы затем обратиться через CSS к группе элементов, у которых задан одинаковый класс, и применить для него определенные свойства (к примеру, сменить цвет текста, размер шрифта и так далее).

Существует также атрибут id, который подобно атрибуту class позволяет выбирать элементы на HTML странице.

Разница между атрибутом class и атрибутом id в том, что class выбирает группу элементов (даже если он дан одному элементу — его в последствии можно дать и другому), а id выбирает уникальный элемент (больше элемента с таким id не должно быть на странице сайта, иначе будет конфликт).

Как понять, что давать элементу — класс или id? Класс дается тем элементам, которые повторяются на страницах сайта (чтобы по несколько раз не писать один и тот же CSS код). Даже если у вас сейчас данный элемент один, но вы чувствуете, что похожие элементы могут появится в дальнейшем — давайте этому элементу класс. Если же вы уверены, что такой элемент уникальный — то давайте ему id. Хотя в настоящее время есть тенденция к тому, чтобы всем элементам давать класс, а id оставить для JavaScript, но она не является общепринятой.

Элементу можно задать несколько классов, в этом случае их следует перечислять через пробел.

Названия классов должны быть набраны английскими буквами, цифрами, без пробелов (пробел отделяет классы друг от друга, вместо него можно использовать подчеркивание или дефис). Классы не должны начинаться с цифры (в HTML5 уже можно, но не будет работать в старых браузерах).

Имена классам следует давать на английском языке (а не на русском, просто английскими буквами!). Имена должны быть осмысленными, отражать суть класса.

Пример

Давайте всем абзацам с классом test зададим красный цвет текста:

Абзац с классом test.

Контрольный абзац без класса.

.test < color: red; >

Пример . Несколько классов для элемента

А здесь давайте первому абзацу зададим несколько классов — test1 и test2 (запишем их через пробел). Класс test1 задает красный цвет тексту, а класс test2 задает размер шрифта в 20px . Второму абзацу дан только класс test1 (этот абзац станет красным), а третьему абзацу — класс test2 (этот абзац будет иметь размер шрифта в 20px). Первый абзац, у которого два класса, будет иметь одновременно и красный цвет и размер шрифта в 20px :

Абзац с двумя классами test1 и test2.

Абзац с классом test1.

Абзац с классом test2.

Контрольный абзац без классов.

.test1 < color: red; >.test2 < font-size: 20px; >

class

Глобальный атрибут class это разделённый пробелом список регистров зависимых классов элемента. Классы позволяют CSS и Javascript выбирать и получать доступ с помощью селекторов класса или функций, таких как методы DOM document.getElementsByClassName .

Интерактивный пример

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

Спецификация

Specification
HTML Standard
# global-attributes:classes-2

Совместимость с браузерами

BCD tables only load in the browser

Смотреть также

  • Все глобальные атрибуты.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *