2009-03-06 14 views
0

J'ai un registre des classes et types en Python 2.5, comme suit:Quelle est la meilleure façon de trouver le type correspondant le plus proche d'un type existant?

class ClassA(object): 
    pass 

class ClassB(ClassA): 
    pass 

MY_TYPES = { 
    basestring : 'A string', 
    int : 'An integer', 
    ClassA : 'This is ClassA or a subclass', 
} 

Je voudrais être en mesure de passer des types à une fonction, et lui donner l'aspect le plus proche type de correspondance dans la hiérarchie. Donc, en regardant str renverrait "A string" et en levant ClassB retournerait "This is ClassA or a subclass" Le problème est, je ne sais pas comment trouver la superclasse (ou, plutôt, tracer la chaîne MRO) d'un objet de type.

Quelle est la meilleure façon de gérer cela?

Répondre

4
from inspect import getmro 
[st for cls, st in MY_TYPES.items() if cls in getmro(ClassB)] 

['This is ClassA or a subclass'] 

ou si vous n'êtes intéressé que le premier match (es) version générateur:

(st for cls, st in MY_TYPES.iteritems() if cls in getmro(ClassB)) 
+0

bien! J'oublie toujours d'inspecter ... doit être un défaut de personnalité ou quelque chose. –

2

Pour obtenir les superclasses d'une classe, utilisez __bases__:

class ClassA(object): 
    pass 

class ClassB(ClassA): 
    pass 

print ClassB.__bases__ 
(<class '__main__.ClassA'>,) 

Prenez garde des choses comme int, cependant. La base de tous ces éléments sera <type 'object'>. Vous devrez effectuer des tests et des itérations pour faire correspondre les touches dict que vous avez listées dans votre exemple.

Une autre option serait d'utiliser isinstance sur n'importe quelle instance d'objet, ou issubclass sur les paramètres, en testant chacun contre vos clés dict. Certains considèrent isinstance et ses semblables comme la marque du diable, mais c'est la vie. Encore une fois, cependant, méfiez-vous d'utiliser issubclass avec ints et autres types de ce type. Vous aurez probablement besoin de combiner quelques approches, compte tenu de vos clés dict.

0

C'est vraiment un emploi pour les fonctions génériques. Voir PEAK-Rules et PEP 3124. Les fonctions génériques vous permettront d'envoyer des fonctions arbitraires basées sur des types d'arguments, ou même des expressions plus complexes.

Ou si vous êtes vraiment un ventouse pour la punition, en témoigner chapter de Practical Common Lisp.

1

(st pour cls, st dans MY_TYPES.iteritems() si NFT dans getmro (ClassB))

La façon plus simple d'écrire ce serait:

(st for cls, st in MY_TYPES.iteritems() if issubclass(ClassB, cls)) 

Cependant, cette ne trouve pas le match "le plus proche"; Si 'object' était dans la recherche, cela pourrait correspondre à tout! Si vous aviez des choses qui étaient sous-classes d'autres choses dans la recherche, ou que vous vouliez soutenir l'héritage multiple, vous auriez à choisir celui qui a été le premier MRO:

for cls in inspect.getmro(ClassB): 
    if cls in MY_TYPES: 
     print MY_TYPES[cls] 
     break 
else: 
    print 'Dunno what it is' 

Quoi qu'il en soit ... Je considérerait généralement les recherches de type comme un peu d'une odeur de code, y at-il pas de meilleure façon de faire ce que vous voulez?

+0

J'utilise une bibliothèque de widgets et une bibliothèque de base de données. J'ai besoin d'assigner des widgets pour afficher des champs de base de données particuliers d'une manière flexible. Dire qu'un "TextWidget" devrait être utilisé pour afficher une "basetring" est la meilleure façon de voir. Et ne dépend pas d'un ensemble particulier de types de base de données à définir. –

Questions connexes