“Ne peut pas instancier une classe abstraite ... avec des méthodes abstraites” de la classe qui ne doit avoir aucune méthode abstraite
Prendre exemple minimal:
import abc
class FooClass(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def FooMethod(self):
raise NotImplementedError()
def main():
derived_type = type('Derived', (FooClass,), {})
def BarOverride(self):
print 'Hello, world!'
derived_type.FooMethod = BarOverride
instance = derived_type()
De course main()
vous obtient:
TypeError: Can't instantiate abstract class Derived with abstract methods FooMethod
(À l'exception se produit sur la instance = derived_type()
ligne.)
Mais FooMethod
ne devrait pas être abstrait: j'ai remplacé avec BarOverride
. Alors, pourquoi est-ce que cela soulève des exceptions?
Avertissement: Oui, je pourrais utiliser explicitement class
de la syntaxe, et de faire exactement la même chose. (Et même mieux, je peux le faire fonctionner!) Mais c'est un minimum de cas de test, et le plus grand exemple est de créer dynamiquement des classes. 🙂 Et je suis curieux de savoir pourquoi cela ne fonctionne pas.
Edit: Et pour empêcher les autres évident de non-réponse: je ne veux pas passer BarOverride
dans le troisième argument de type
: Dans l'exemple réel, BarOverride
doit avoir derived_type
lié à elle. Il est plus facile de le faire si je peux définir BarOverride
après la création de derived_type
. (Si je ne peux pas faire cela, alors pourquoi?)
FooMethod
dans le dictionnaire, alors que la création de la classe?BarOverride
, dans l'exemple réel, doit avoir de la classe dérivée lié à elle. Création de la fonction par la suite est la meilleure façon d'atteindre cet.Je n'ai pas ce point. Qu'entendez-vous par "doit avoir la classe dérivée lié à elle"?
OriginalL'auteur Thanatos | 2011-11-10
Vous devez vous connecter pour publier un commentaire.
Parce que les docs disent donc:
Une métaclasse est seulement appelé lorsqu'une classe est définie. Lorsque
abstractmethod
a marqué une classe de base abstraite que le statut ne changera pas plus tard.OriginalL'auteur Jochen Ritzel
Jochen est droit; les méthodes abstraites sont fixés à la création de classes et de ne pas m'modifié juste parce que vous réaffecter un attribut.
Vous pouvez supprimer manuellement de la liste des méthodes abstraites en faisant
ou
ainsi que
setattr
, afin de ne pas toujours penser queFooMethod
est abstraite.OriginalL'auteur agf
Je sais que ce sujet est vraiment vieux, mais... C'est vraiment une bonne question.
Cela ne fonctionne pas car l'abc peut seulement vérifier les méthodes abstraites pendant instatiation de types, c'est, quand
type('Derived', (FooClass,), {})
est en cours d'exécution. Tout setattr fait après ce n'est pas accessible à partir de abc.Donc, setattr pas travailler, buuut...
Votre problème de relever le nom d'une classe qui n'a pas été préalablement déclarée ou définie semble insoluble:
J'ai écrit un petit métaclasse qui vous permet d'utiliser un espace réservé "clazz" pour accéder à toute la classe qui finira par être la méthode que vous écrivez en dehors d'une définition de classe.
De cette façon, vous n'obtiendrez pas TypeError de l'abc de plus, puisque vous pouvez maintenant définir votre méthode AVANT de instatiating votre type, et ensuite de le passer à la dict argument. Abc verront cela comme une bonne méthode de remplacement.
Aaand, avec la nouvelle métaclasse vous pouvez vous référer à l'objet de classe au cours de cette méthode.
Et c'est super, parce que maintenant vous pouvez utiliser super! =P
Je peux deviner que vous étiez inquiet au sujet de la trop...
Prendre un coup d'oeil:
La sortie est:
OriginalL'auteur rbertoche
Bien, si vous devez le faire de cette façon, alors vous pouvez simplement passer un mannequin dict
{'FooMethod':None}
comme troisième argument de type. Cela permetderived_type
pour satisfaire ABCMeta de l'exigence que toutes les méthodes abstraites être substituée. Plus tard, vous pouvez indiquer le vraiFooMethod
:FooMethod
abstrait, parce que si le type de création et desetattr
sont séparés, vous pouvez instancierderived_type
avant réglage de la méthode.Une classe de type
ABCMeta
devrait être singe-patchable juste comme n'importe quelle autre classe. En fournissant le troisième argument, vous reconnaissez queDerived
doit définirFooMethod
. Qui n'a pas de bar pour vous de changer votre esprit au sujet de sa mise en œuvre plus tard.OriginalL'auteur unutbu