В Python, каково обоснование того, что object.__setattr__
и type.__setattr__
вызывают AttributeError
во время атрибута update, если у типа есть атрибут, который является дескриптором data без метода __set__
? Аналогичным образом, в чем причина того, что object.__delattr__
и type.__delattr__
вызывают AttributeError
во время удаления атрибута, если у типа есть атрибут, который является дескриптором data без метода __delete__
?
Я спрашиваю об этом, потому что заметил, что object.__getattribute__
и type.__getattribute__
не вызывают AttributeError
во время поиска атрибута, если тип имеет атрибут, который является данными дескриптор без метода __get__
.
Вот простая программа, иллюстрирующая различия между поиском атрибута с помощью object.__getattribute__
, с одной стороны (AttributeError
не возбуждается), и обновлением атрибута с помощью object.__setattr__
и удалением атрибута с помощью object.__delattr__
, с другой стороны (AttributeError
возбуждается):
class DataDescriptor1: # missing __get__
def __set__(self, instance, value): pass
def __delete__(self, instance): pass
class DataDescriptor2: # missing __set__
def __get__(self, instance, owner=None): pass
def __delete__(self, instance): pass
class DataDescriptor3: # missing __delete__
def __get__(self, instance, owner=None): pass
def __set__(self, instance, value): pass
class A:
x = DataDescriptor1()
y = DataDescriptor2()
z = DataDescriptor3()
a = A()
vars(a).update({'x': 'foo', 'y': 'bar', 'z': 'baz'})
a.x
# actual: returns 'foo'
# expected: returns 'foo'
a.y = 'qux'
# actual: raises AttributeError: __set__
# expected: vars(a)['y'] == 'qux'
del a.z
# actual: raises AttributeError: __delete__
# expected: 'z' not in vars(a)
Вот еще одна простая программа, иллюстрирующая различия между поиском атрибута по type.__getattribute__
с одной стороны (AttributeError
не вызывается), и обновлением атрибута по type.__setattr__
и удалением атрибута по type.__delattr__
с другой стороны (AttributeError
возбуждается):
class DataDescriptor1: # missing __get__
def __set__(self, instance, value): pass
def __delete__(self, instance): pass
class DataDescriptor2: # missing __set__
def __get__(self, instance, owner=None): pass
def __delete__(self, instance): pass
class DataDescriptor3: # missing __delete__
def __get__(self, instance, owner=None): pass
def __set__(self, instance, value): pass
class M(type):
x = DataDescriptor1()
y = DataDescriptor2()
z = DataDescriptor3()
class A(metaclass=M):
x = 'foo'
y = 'bar'
z = 'baz'
A.x
# actual: returns 'foo'
# expected: returns 'foo'
A.y = 'qux'
# actual: raises AttributeError: __set__
# expected: vars(A)['y'] == 'qux'
del A.z
# actual: raises AttributeError: __delete__
# expected: 'z' not in vars(A)
Я бы ожидал, что словарь экземпляра будет изменен вместо получения AttributeError
для обновления атрибута и удаления атрибута. Поиск атрибута возвращает значение из словаря экземпляра, поэтому мне интересно, почему обновление атрибута и удаление атрибута также не используют словарь экземпляра (как они делали бы, если бы у типа не было атрибута, который является дескриптором данных).