Атрибут - это переменная, которая просматривается на другом объекте с использованием точечного синтаксиса: obj.attribute
. Путь Python разработан, поиск атрибутов может делать множество вещей, и это разнообразие иногда может приводить к ошибкам, если вы действительно не понимаете, что происходит (это то, о чем предупреждает документация, на которую вы ссылаетесь).
Основная проблема заключается в том, что поиск атрибута может найти либо значение, хранящееся в словаре экземпляра объекта, либо он может найти что-то из класса объекта (или базового класса, если происходит наследование). Методы - это функции, хранящиеся в классе, но вы обычно используете их, просматривая их на экземпляре (который «связывает» метод, вставляя объект в качестве первого аргумента при вызове метода).
Точная последовательность того, что проверяется, когда немного сложна (я описал полный процесс в an answer to another question), но на самом базовом уровне атрибуты экземпляра обычно имеют приоритет над атрибутом класса.
Если атрибут экземпляра и атрибут класса с тем же именем существуют, обычно доступен только атрибут экземпляра. Это может быть очень запутанным, если оно непреднамеренно.
Рассмотрим следующий код:
class Foo(object):
def __init__(self, lst):
self.lst = lst
def sum(self):
self.sum = sum(self.lst)
return self.sum
f = Foo([1,2,3])
print(f.sum())
print(f.sum())
В нижней части этого кода, мы делаем два одинаковых вызовов. Первый работает просто отлично, но второй вызывает исключение.
Это потому, что при первом поиске f.sum
мы находим метод в классе Foo
. Мы можем назвать метод без проблем. Проблема связана с тем, что метод sum
присваивает результат его вычисления (сумма элементов в self.lst
) атрибуту экземпляра, также называемому sum
. Это скрывает метод sum
.
Когда второй f.sum()
вызов ищет f.sum
, он находит атрибут экземпляра, содержащий целое число 6
, а не ожидаемый метод. Целое число не является вызываемым, поэтому мы получаем исключение.
Решение, конечно же, не должно использовать одно и то же имя для метода и атрибута. Вышеприведенный код - довольно простой пример. Ошибки, вызванные такими вещами в более сложном коде, могут быть намного сложнее выяснить.
Если вы пишете код, который добавляет атрибуты к объектам, о которых вы мало что знаете, вы должны быть осторожны, чтобы избежать общих имен. Если вы пишете класс mixin, подумайте о двух ведущих символах подчеркивания в именах атрибутов, чтобы вызвать манипулирование именем Python, которое предназначено именно для такого рода ситуаций.
Ваши объяснения довольно просты. Итак, мне кажется, что связанная с документацией информация означает «атрибут данных» = «атрибут экземпляра», «атрибут метода» = «атрибут класса». Если я ошибаюсь, исправьте меня. –
Да, это так. Я думаю, что документация может быть довольно старой и не совсем обновленной. Конечно, «атрибут экземпляра» и «атрибут класса» в наши дни являются гораздо более распространенными. Стоит также отметить, что реальная ситуация немного сложнее, чем я представил здесь. Некоторые типы атрибутов класса (например, объекты «property») будут иметь приоритет над атрибутами экземпляра. Однако вряд ли вы попадете в эту ситуацию по ошибке. – Blckknght