Comment puis-je créer dynamiquement des classes dérivées d'une classe de base
Par exemple, j'ai une classe de base comme suit:
class BaseClass(object):
def __init__(self, classtype):
self._type = classtype
À partir de cette classe je tire plusieurs autres classes, par exemple
class TestClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Test')
class SpecialClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Special')
Est-il gentil, pythonic façon de créer ces classes dynamiquement par un appel de fonction qui met les nouvelles de la classe dans mon périmètre actuel, comme:
foo(BaseClass, "My")
a = MyClass()
...
Qu'il y aura des commentaires et des questions pourquoi j'ai besoin de ceci: Les classes dérivées tous ont exactement la même structure interne, avec cette différence, que le constructeur prend un certain nombre de indéfini d'arguments. Ainsi, par exemple, MyClass
prend les mots-clés a
alors que le constructeur de la classe TestClass
prend b
et c
.
inst1 = MyClass(a=4)
inst2 = MyClass(a=5)
inst3 = TestClass(b=False, c = "test")
Mais ils ne devraient JAMAIS utiliser le type de la classe comme argument d'entrée comme
inst1 = BaseClass(classtype = "My", a=4)
J'ai eu ce travail, mais préfère l'autre sens, c'est à dire de créer dynamiquement des objets de la classe.
- Juste pour être sûr, vous voulez que le type de l'instance de changer en fonction des arguments fournis? Comme si je donne un
a
il sera toujoursMyClass
etTestClass
ne seront jamais prendre unea
? Pourquoi ne pas déclarer toutes les 3 arguments dansBaseClass.__init__()
mais par défaut de tous àNone
?def __init__(self, a=None, b=None, C=None)
? - Je ne peux rien déclarer dans la classe de base, que je ne connais pas tous les arguments que je pourrais utiliser. Je pourrais avoir 30 clases avec 5 différents arguments de chacun, afin de déclarer 150 arguments dans le constructur n'est pas une solution.
Vous devez vous connecter pour publier un commentaire.
Ce morceau de code permet de créer de nouvelles classes dynamiques
les noms et les noms de paramètre.
Le paramètre de vérification dans
__init__
juste ne permet pasles paramètres inconnus, si vous avez besoin d'autres vérifications, comme
type, ou qu'ils sont obligatoires, il suffit d'ajouter la logique
il y a:
Et cela fonctionne comme ceci, par exemple:
Je vois que vous demandez pour l'insertion de la dynamique des noms dans la désignation portée --
maintenant, que n'est pas considéré comme une bonne pratique en Python - soit vous avez
les noms de variable, connu au codage de temps, ou de données et les noms appris lors de l'exécution
sont plus "données" que des "variables" -
Ainsi, vous pouvez simplement ajouter vos classes à un dictionnaire et à les utiliser à partir de là:
Et si votre conception doit absolument les noms de venir dans le champ d'application,
il suffit de faire la même chose, mais utiliser le dictionnaire renvoyé par la
globals()
appel, au lieu de l'arbitraire d'un dictionnaire:
(Il serait en effet possible pour la classe de l'usine de fonction pour insérer le nom de la dynamique sur la portée globale de l'appelant, mais c'est encore pire de la pratique, et n'est pas compatible entre les implémentations de Python. La façon de le faire serait d'obtenir de l'appelant cadre de l'exécution, par le biais de sys._getframe(1) et paramètre le nom de la classe dans le cadre global dans son dictionnaire
f_globals
attribut).mise à jour, le tl;dr: Cette réponse était devenu populaire, toujours très particulier à la question du corps. La réponse générale sur la façon de
"créer dynamiquement des classes dérivées d'une classe de base"
Python est un simple appel à
type
en passant le nouveau nom de la classe, un tuple avec la baseclass(es) et le__dict__
corps pour la nouvelle classe comme ceci:mise à jour
Toute personne ayant besoin de cette devraient également vérifier le l'aneth projet - qu'il prétend être en mesure de cornichon et unpickle classes comme pickle ne des objets ordinaires, et ont vécu dans certaines de mes tests.
BaseClass.__init__()
serait mieux que lessuper(self.__class__).__init__()
, qui joue plus bien quand les nouvelles classes sont sous-classé. (Référence: rhettinger.wordpress.com/2011/05/26/super-considered-super)super
ci-dessus et de créer une sous-classe de la dynamique d'une classe créée pour la comprendre; Et, d'autre part, dans ce cas, vous pouvez avoir la baseclass général objectfrom qui appeler__init__
.__init__
deBaseClass
est appelée avec un argument, mais en faitBaseClass.__init__
prend toujours un arbitraire liste des mots clés les arguments. Deuxièmement, la solution ci-dessus définit tous les permis des noms de paramètres comme les attributs, ce qui n'est pas ce que je veux. TOUT argument doit aller àBaseClass
, mais lequel je sais que lors de la création de la classe dérivée. Je vais probablement mettre à jour la question ou demander plus de précision pour le rendre plus clair.super()
je le disais donneTypeError: must be type, not SubSubClass
. Si je comprends bien, cela provient de la premier argumentself
de__init__()
, qui est unSubSubClass
où untype
objet est prévu: cela semble lié au faitsuper(self.__class__)
est un indépendant super objet. Quel est son__init__()
méthode? Je ne suis pas sûr de qui une telle méthode pourrait nécessiter un premier argument de typetype
. Pourriez-vous expliquer? (Note de côté: monsuper()
approche, en effet, n'a pas de sens, ici, parce que__init__()
a une variable de la signature.)__init__
de la baseclasswith qu'un seul paramètre ne sont que deux ordinaire lignes, et ne fait pas partie de la "solution" de créer les classes dynamiquement À ce stade, il n'est pas assez clair pour moi ce que vous avez besoin - mais vous certainy pouvez modifier ces comportements dans le code ci-dessus.type()
est la fonction qui crée les classes (et en particulier les sous-classes):TypeError
que dit__init__() takes exactly 2 arguments (1 given)
. J'ai trouvé que l'ajout de quelque chose (rien?) pour combler l'écart suffirait. Par exemple,obj = SubClass('foo')
s'exécute sans erreur.SubClass
est une sous-classe deBaseClass
dans la question etBaseClass
prend un paramètre (classtype
, qui est'foo'
dans votre exemple).Pour créer une classe avec une dynamique de la valeur de l'attribut, la caisse le code ci-dessous.
NB. Ce sont des extraits de code dans le langage de programmation python