Оскільки 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це.