Depuis la version 2.6 de Python, avec l'introduction de classes de base abstraites, isinstance
(utilisé sur Abc, pas de classes de béton) est maintenant considéré comme parfaitement acceptable. Plus précisément:
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
C'est une copie exacte (en changeant seulement le nom de la classe) de l' Iterable
tel que défini dans l' _abcoll.py
(un détail d'implémentation de collections.py
)... la raison pour laquelle cela fonctionne comme vous le souhaitez, tout en collections.Iterable
ne l'est pas, c'est que ce dernier va le mile supplémentaire pour s'assurer des chaînes itératif, en appelant Iterable.register(str)
explicitement juste après cette class
déclaration.
Bien sûr, il est facile de compléter __subclasshook__
en retournant False
avant l' any
appel à d'autres classes que vous souhaitez exclure expressément de votre définition.
En tout cas, après avoir importé ce nouveau module, en myiter
, isinstance('ciao', myiter.NonStringIterable)
sera False
, et isinstance([1,2,3], myiter.NonStringIterable)
sera True
, comme vous le demande-et en Python 2.6 et plus tard, ceci est considéré comme la bonne façon de constituer de tels contrôles... définir une classe de base abstraite et vérifiez isinstance
sur il.