Асимметричное поведение для классов __getattr__, newstyle vs oldstyle

я пишу здесь впервые, извините, если сообщение не указано или слишком длинное.

Мне было интересно узнать больше о том, как атрибуты объектов выбираются при необходимости. Поэтому я прочитал документацию по Python 2.7 под названием «Модель данных» здесь , Я встретил __getattr__ и, чтобы проверить, понял ли я его поведение, я написал эти простые (и неполные) упаковщики строк.

class OldStr:
  def __init__(self,val):
    self.field=val

  def __getattr__(self,name):
    print "method __getattr__, attribute requested "+name

class NewStr(object):
  def __init__(self,val):  
    self.field=val

  def __getattr__(self,name):
    print "method __getattr__, attribute requested "+name

Как вы можете видеть, они одинаковы, за исключением того, что они являются классами старого стиля и нового стиля. Поскольку в цитируемом тексте написано, что __getattr__ «Вызывается, когда поиск атрибута не нашел атрибут в обычных местах», я хотел попробовать + операция над двумя экземплярами этих классов, чтобы увидеть, что произошло, ожидая идентичного поведения.

Но результаты, которые я получил, немного озадачили меня:

>>> x=OldStr("test")
>>> x+x
method __getattr__, attribute requested __coerce__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

Хорошо! Я не определил метод для __coerce__ (хотя ожидал запроса на __add__, неважно :), поэтому __getattr__ вмешались и вернули бесполезную вещь. Но тогда

>>> y=NewStr("test")
>>> y+y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NewStr' and 'NewStr'

Почему это асимметричное поведение между __getattr__ в классах старого и нового классов при использовании встроенного оператора, такого как +? Может ли кто-нибудь помочь мне понять, что происходит, и в чем была моя ошибка при чтении документации?

Большое спасибо, ваша помощь очень ценится!

7 голосов | спросил Filippo 5 PM00000060000001531 2010, 18:39:15

3 ответа


0

См. Поиск специального метода для классов нового стиля .

Специальные методы непосредственно ищутся в объекте класса, объектах экземпляра и, следовательно, __getattr__() и __getattribute__() обойдены. По той же причине instance.__add__ = foobar не работает.

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

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

ответил lunaryorn 5 PM00000070000002131 2010, 19:00:21
0

Ваши функции __getattr__ ничего не возвращают. Я не знаю, почему класс старого стиля выполняет __getattr__, прежде чем искать __add__, но это так, и он пытается вызвать возвращаемое значение, которое равно None.

Класс нового стиля делает все правильно: вы не определили __add__, поэтому он не знает, как их добавить .

ответил Katriel 5 PM00000060000001831 2010, 18:47:18
0

Дополнительная информация из документации по Python:

http://docs.python.org/reference/datamodel .html # Customizing-атрибут доступа

ответил adamk 5 PM00000060000002931 2010, 18:49:29

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132