2012-10-13 2 views
8

В дополнение к обходным атрибутам экземпляра в интересах правильности, неявный специальный поиск метода обычно также обходит метод __getattribute__() даже метакласса объекта.Какие специальные методы обходят __getattribute__ в Python?

The docs отметить специальные методы, такие как __hash__, __repr__ и __len__, и я знаю из опыта, он также включает в себя __iter__ для Python 2.7.

Цитирую an answer to a related question:

«Magic __methods__() обрабатываются специально: они внутренне назначены на„слоты“в структуре типа данных, чтобы ускорить их просмотровых, и они только смотрели в них слоты «.

В поисках улучшения ответа на вопрос another question, мне нужно знать: какие методы, в частности, мы говорим?

+0

Какие методы назначены слотам? –

+7

Я думаю, что каждый метод указан [здесь] (http://docs.python.org/reference/datamodel.html#specialnames). В любом случае учтите, что это применимо только в том случае, если вы вызываете метод, используя «его синтаксис». Например, 'a + 5' не будет вызывать' __getattribute__', а 'a .__ add __ (5)' * будет * вызывать его. В основном '__getattribute__' вызывается всякий раз, когда вы используете точку (' .') для доступа к атрибуту. – Bakuriu

+0

@ Бакуриу: Очень информативно, спасибо. – porgarmingduod

ответ

4

Вы можете найти ответ в Python3 documentation для object.__getattribute__, в котором говорится:

Вызывается безоговорочно реализовать атрибут доступы для экземпляров класса. Если класс также определяет __getattr__(), то номер не будет вызываться, если только __getattribute__() не называет его явно или вызывает AttributeError. Этот метод должен возвращать значение атрибута (вычисленное) или вызывать исключение AttributeError. В , чтобы избежать бесконечной рекурсии в этом методе, его реализация должна всегда вызывать метод базового класса с тем же именем для доступа к всем атрибутам, которые ему нужны, например, к объекту. __getattribute__(self, name).

Примечание

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

также this страница объясняет, как именно это «оборудование» работает. По существу __getattribute__ вызывается только при доступе к атрибуту с помощью оператора . (точка) (а также по hasattr, как указал Зауголкин).

Обратите внимание, что страница не определяет, какие специальные методы неявно посмотрел вверх, так что я считаю, что это держать для всех из них (которые вы можете найти here.

+0

Вы действительно проверили? я проверял 2.7.9, и кажется, что документы не совсем правы. –

1

Проверено 2.7.9

не мог «т найти способ обойти вызов __getattribute__, с любым из магических методов, которые находятся на object или type:

# Preparation step: did this from the console 
# magics = set(dir(object) + dir(type)) 
# got 38 names, for each of the names, wrote a.<that_name> to a file 
# Ended up with this: 

a.__module__ 
a.__base__ 
#... 

Поместите это в beginnin g этого файла, который я переименовал в правильный модуль python (asdf.ру)

global_counter = 0 

class Counter(object): 
    def __getattribute__(self, name): 
     # this will count how many times the method was called 
     global global_counter 
     global_counter += 1 
     return super(Counter, self).__getattribute__(name) 

a = Counter() 
# after this comes the list of 38 attribute accessess 
a.__module__ 
#... 
a.__repr__ 
#... 

print global_counter # you're not gonna like it... it printer 38 

Тогда я также пытался получить каждое из этих имен по getattr и hasattr -> тот же результат. __getattribute__ был вызван каждый раз.

Итак, если у кого-то есть другие идеи ... Мне было слишком лениво заглянуть внутрь кода C для этого, но я уверен, что ответ лежит где-то там.

Так или есть что-то, что я не получаю, или документы лежат.

+1

Если я правильно помню, мой вопрос касался 'repr (a)' в отличие от '.__ repr __()'. Прошло некоторое время с тех пор, как я был в этом, но я предполагаю, что вы получите версию getattribute, потому что вы просматриваете атрибуты, тогда как встроенные методы, о которых мы говорим (глобальные 'repr', а не' __repr__') обходят существование '__repr__'. – porgarmingduod

+0

Переопределите '__getattribute__', чтобы выдать печать всякий раз, когда он вызывается, а затем выполните:' Counter ('a') + Counter ('a') 'и убедитесь, что он ничего не печатает. Потому что это в обход стандартного имени, и он нажимает 'Counter .__ dict __ ['__ add __']' прямо или какую-то такую ​​глупость во имя оптимизации. – justanr

Смежные вопросы