Начиная с Python 2.6, с введением абстрактных базовых классов isinstance(используемых в ABC, а не в конкретных классах) теперь считается вполне приемлемым. В частности:
from abc import ABCMeta, abstractmethod
class NonStringIterable:
__metaclass__ = ABCMeta
@abstractmethod
def __iter__(self):
while False:
yield None
@classmethod
def __subclasshook__(cls, C):
if cls is NonStringIterable:
if any("__iter__" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
Это точная копия (изменение только имени класса), Iterableкак определено в _abcoll.py(детали реализации collections.py) ... причина, по которой это работает так, как вы хотите, а collections.Iterableне нет, заключается в том, что последний делает все возможное, чтобы гарантировать, что строки считается повторяемым, вызывая Iterable.register(str)явным образом сразу после этого classоператора.
Конечно, это легко дополнить __subclasshook__, вернув Falseперед anyвызовом другие классы, которые вы хотите специально исключить из своего определения.
В любом случае, после того, как вы импортировали этот новый модуль, как myiter, isinstance('ciao', myiter.NonStringIterable)будет Falseи isinstance([1,2,3], myiter.NonStringIterable)будет True, как вы запрашиваете - и в Python 2.6 и более поздних версиях это считается правильным способом реализации таких проверок ... определить абстрактный базовый класс и проверьте isinstanceэто.