2016-07-31 6 views
0

Согласно Python 2.7.12 документации:Зачем использовать объект .__ setattr __ (self, name, value) только в классах нового стиля?

Если __setattr__() хочет присвоить атрибут экземпляра, он должен не просто выполнить self.name = value - это вызовет рекурсивный вызов к себе. Вместо этого он должен вставить значение в словарь атрибутов экземпляра, например, self.__dict__[name] = value. Для классов новых классов, а не для доступа к экземпляру словаря, он должен вызывать метод базового класса с тем же именем, например object.__setattr__(self, name, value).

Однако следующий код работает, как и следовало ожидать:

class Class(object): 
    def __setattr__(self, name, val): 
     self.__dict__[name] = val; 

c = Class() 
c.val = 42 
print c.val 

Я знаю super(Class, obj).__setattr__(name, value) может обеспечить __setattr__ методы всех базовых классов назвать, но классический класс может наследовать от классов баз. Так почему это рекомендуется только для новых классов стиля?

Или, с другой стороны, почему это не рекомендуется для классических классов?

+1

* Так почему же это рекомендуется только для новых классов стиля? * Вызов '__setattr__' вместо работы с словарем экземпляра напрямую позволяет суперклассу« контролировать »происходящее. Подумайте об этом подходе в качестве преимущества новых классов стиля.Вероятно, это рекомендуется для всех классов, но классы старого стиля, которые не наследуют *, не имеют * суперкласса с вызываемым методом '__setattr__'. – jedwards

+1

@jedwards Да, потому что для классических классов нет 'classobj .__ setattr__', а для новых классов стилей - только' object .__ setattr__'. –

+0

Вы совершенно правы. Мое мнение состояло в том, что я рассматривал предложение, которое вы придаете жирным шрифтом, а не столько отвращение от непосредственного использования экземпляра dict (как вы показали, во многих случаях он отлично работает, и, как показал Мартийн, бывают случаи, когда он не будет), но больше * поощрения * использовать '__setattr__', что позволяет контролировать суперкласс и * использовать более новые функции, такие как дескрипторы. Извините, если я был неясен :) – jedwards

ответ

3

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

От documentation on slots:

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

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

Доступ к слотам вместо этого осуществляется путем добавления data descriptors на класс; объект с __set__ и/или __del__ методов для каждого такого атрибута.

Другим примером дескрипторов данных является property() objects, которые имеют функцию setter или deleter. Установка ключа с тем же именем, что и такой объект дескриптора в __dict__, будет проигнорирована, поскольку дескрипторы данных заставляют поиск атрибутов полностью обходить __dict__.

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

+0

Возможно, «Установка ключа для такого объекта в' __dict__' будет проигнорирована »должна быть« Установка ключа для объекта, класс которого использует дескрипторы данных в '__dict__', будет проигнорирован» сделать его более ясным? –

+0

@sunqingyao: рассматриваемый объект является дескриптором данных класса. –