?

Log in

No account? Create an account

"Упрощённая форма получения гражданства" по-питоновски. - Узором созвездий по мантии ночи

10.10.2012, Среда

18:15:00 - "Упрощённая форма получения гражданства" по-питоновски.

Previous Entry Поделиться Next Entry

Полезши искать ("я точно помню, это есть, но не помню, как именно") сопсоб проверить (в питоне) произвольный объект на возможность итерироваться по нём, дорыл до isinstance(some_object, collections.Iterable). Затем уточнил, что объекту для успешного прохождения этой проверки вовсе не надо порисходить от collections.Iterable, достаточно иметь у себя метод __iter__. Ну, хорошо, если для проверки на isinstance необязательно быть объектом этого класса или его субкласса, значит это тоже где-то перехватывается. И, конечно, нашёлся метод __instancecheck__.
После чего и родилась сентенцеия из заголовка -- чтобы некий класс признал данный объект своим, ему вовсе необязательно реально от того класса происходить, если у того класса определены упрощённые условия признания своих.

This entry was originally posted at http://arilou.dreamwidth.org/885026.html. Please comment there using OpenID.

Comments:

[User Picture]
From:phd
Date:10.10.2012 15:49:31
(Link)
А что ты будешь делать, если __iter__ есть, а __instancecheck__ нету?
(Ответить) (Thread)
[User Picture]
From:besm6
Date:10.10.2012 19:33:53
(Link)
Я так понял, что __iter__ у проверяемого, а __instancecheck__ у проверяющего...
(Ответить) (Parent) (Thread)
[User Picture]
From:phd
Date:10.10.2012 19:54:09
(Link)
Должно быть __instancecheck__ (метод класса) у проверяемого, а isinstance (функция) у проверяющего. __iter__, конечно, у проверяемого. Ну так и проверять надо __iter__, а не isinstance. Проверять надо протокол, а не тип.
(Ответить) (Parent) (Thread)
[User Picture]
From:besm6
Date:11.10.2012 04:08:14
(Link)
Знаешь, Олег, http://docs.python.org/reference/datamodel.html с тобой не согласно, а с Эленельдилем как раз согласно.

Ну и эта, isinstance (функция) не может быть у проверяющего - она функция, а не метод.

Edited at 2012-10-11 04:09 (UTC)
(Ответить) (Parent) (Thread)
[User Picture]
From:phd
Date:11.10.2012 10:05:53
(Link)
Мы запутались в терминах. У нас много участников процесса, а мы их обозвали двумя словами «проверяемый» и «проверяющий». Есть код, который пишет Эль, и этот код вызывает isinstance. Есть абстрактный класс Iterable. И есть некий экземпляр, который Эль с помощью isinstance хочет проверить на принадлежность к классу Iterable, хотя на самом деле он хочет проверить наличие метода __iter__. Единственное, чего я не знаю — это начиная с какой версии Python класс Iterable проверяет __iter__. Видимо, уже с 2.6:
$ python
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Test(object):
...     def __iter__(self):
...         pass
... 
>>> test = Test()
>>> import collections
>>> isinstance(test, collections.Iterable)
True
(Ответить) (Parent) (Thread)
[User Picture]
From:besm6
Date:11.10.2012 11:32:46
(Link)
Угу. С 2.6, потому что там в документации было вполне конкретно сказано, что __instancecheck__ появился в 2.6.

А фигня в том, что в Питоне, сколь я помню, нет абстракции для протокола. Вот и пытаются городить проверку протоколов на наследовании. Ведь collections.Iterable, по названию, не класс в смысле наследования, а протокол (интерфейс в жабной терминологии, и как раз класс в хаскельной). В хаскеле и жабе за тебя компилятор проверит.

Проверять один только __iter__ тоже по смыслу плохо. Проверять надо, реализует ли оно _весь_ протокол. В том же хаскеле, не знаю, как в жабе, определяя класс, ты можешь сказать "интерфейс составляют такие-то и такие-то методы, но вот у этих есть дефолтные реализации через другие". И если ты требуешь, скажем, Ord, то можешь смело рассчитывать на

compare :: a -> a -> Ordering
(<) :: a -> a -> Bool
(>=) :: a -> a -> Bool
(>) :: a -> a -> Bool
(<=) :: a -> a -> Bool
max :: a -> a -> a
min :: a -> a -> a


При том, что Minimal complete definition: either compare or &=. То есть, объявляя тип инстансом этого класса, достаточно определить всего один метод, остальное компилятор сам построит. А требуешь ты сразу весь Ord.

(Ну да, можно, допустим, сказать, что в Питоне есть хак, который строит полную поддержку протокола итератора, имея __iter__. Но это ж хак.)
(Ответить) (Parent) (Thread)
[User Picture]
From:phd
Date:11.10.2012 11:42:48
(Link)
Есть в Питоне абстракция для протоколов — называется interface: http://docs.zope.org/zope.interface/. Это не стандартная библиотека, поэтому и абстрактные классы ей не пользуются. Но другие библиотеки и юзеры ею пользуются. Zope она за собой не тащит.
(Ответить) (Parent) (Thread)
[User Picture]
From:arilou
Date:12.10.2012 08:45:59
(Link)
Ну вот, судя по наличию спецметодов __instancecheck__ и __subclasscheck__ проверяющим в питоне объявляется сам тот класс, на инстансность/субклассность которого проверяется некий объект. При этом, надо заметить, что в object этих методов нет (есть, правда, __subclasshook__). Т.е., видимо, isinstance смотрит: если есть __instancecheck__, то отдаёт вопрос на откуп ему, если нет -- ограничивается проверкой дерева классов.

Т.е., возвращаясь к аналогии в моём посте, логичнее сравнивать даже не с гражданством, а с членством в семье. Можно спросить: "Не ваших ли этот?" -- но можно и по записям ЗАГСа проверить. ;)
(Ответить) (Parent) (Thread)
[User Picture]
From:beldmit
Date:10.10.2012 16:58:45
(Link)
Это, кажется, всегда называлось Duck Typing...
(Ответить) (Thread)
[User Picture]
From:phd
Date:10.10.2012 17:51:26
(Link)
__instancecheck__ предназначен не для Duck Typing а, например, для объектов-прокси. Если библиотека L принимает на вход только объекты класса C, то __instancecheck__ позволяет объекту-прокси прикинуться экземпляром C.
(Ответить) (Parent) (Thread)
[User Picture]
From:besm6
Date:10.10.2012 19:37:47
(Link)
По-моему, это Duck Inheritance... В смысле, попытка хоть как-то сделать из системы наследования систему типов strikes back...
(Ответить) (Parent) (Thread)