J'ai un cas où ma classe a une métaclasse personnalisée, qui appelle une méthode de classe de la classe lorsqu'elle la crée, quelque chose comme: (exemple de ce code est dans TASTYPIE .) P> Le problème est si je veux faire: P> Ceci ne fonctionne pas car Je sais que probablement (Python 2.7.) P> P> newbar code> n'est pas encore créé au point
Super code> est invoqué (le flux de programme est toujours en métaclass). Alors, y a-t-il une solution de contournement? P>
get_fields code> pourrait devenir une méthode de métaclasse, mais cela rendrait l'héritage beaucoup plus difficile à mettre en œuvre (vous devriez définir les deux Nouvelle métaclasse et classe elle-même, pas agréable aux développeurs souhaitant prolonger ces cours). P>
3 Réponses :
si newbar code> peut être indisponible lorsque
get_fields code> est invoqué, vous pouvez toujours le trouver dans le MRO de
CLS code>:
@classmethod
def get_fields(cls):
# we can get invoked before NewBar is available in globals,
# so get NewBar from cls.__mro__
NewBar = next(c for c in cls.__mro__
if c.__module__ == __name__ and c.__name__ == 'NewBar')
super(NewBar, cls).get_fields()
...
J'ai fini par utiliser: moi = Suivant (c pour C en CLS .__ MRO__ IF Si c .__ Module__ == __Name__ et c .__ Nom__ == 'Newbar') = "
J'aime le c .__ module__ == __Name __ code> Amélioration! Je vais mettre à jour la réponse.
Qu'en est-il de essayer: Super_class = Newbar; SaufameError: Super_class = CLS; Super (super_class, CLS) .get_fields () code>?
@kropoolik Ça marche, mais il est obscurcié d'une manière différente. Le code dans la réponse indique clairement que nous essayons simplement de trouver newbar code> afin d'appeler
super code> de la manière la plus régulière possible. Dans votre variante, l'invocation
Super code> apparaît encore plus magique que nécessaire.
Une troisième variante telle que essayer: newbar; SaufameError: Newbar = CLS; ... code> conserverait le truc
newbar code>. Cela me rendrait toujours maigre que ce n'est pas Assurez-vous i>, il a réellement trouvé
newbar code>. Peut-être un "affirmer CLS .__ nom__ ==" Newbar`` serait en ordre là-bas.
En effet, nous ne pouvons pas être certains que CLS code> dans
sauf: code> est
newbar code>, mais nous avons 2 cas: appel de notre métaclass (
Newbar. __metaclass __ code>) - Ici
Newbar code> n'a pas fini de construction n'est donc pas disponible en tant que nom global et
CLS code> est le
NEWBAR code> objet. Deuxièmement -
NEWBARDERIVER .__ METACLASS __ CODE>, nous construisons ici une classe qui dérive à partir de
NEWBAR code>, donc newbar est un identifiant valide, à moins que quelqu'un crée une nouvelle classe interne
Newbar. __metaclass __ code> etc. Mais c'est la sorcellerie, pas la programmation. Le
affirmer code> est bien comme pour notifie le codeur que quelque chose est vêlé.
La variante suivante () code> n'est pas garantie de trouver la classe souhaitée, d'être honnête (penser à
newbar.get_fields.im_func (
Essayez: Sauf: assert code> est auto-expliquant.
@KROOOLIK Les exemples pathologiques d'appels vers get_fields code> ne sont heureusement pas sur la table, car nous savons exactement comment
get_fields code> est appelé. (
Le CODE> METACLASS` est en réalité définie dans le cadre de la saveur de goût.) La réponse doit choisir le moins choisir, comme vous le mettez, une solution sorceuse, et c'est parfois une question de goût. Vous pouvez simplement soumettre votre code comme réponse alternative.
basé sur la réponse de @ user4815162342 J'ai trouvé une solution encore plus simple:
Plus simple au détriment de l'exactitude, malheureusement. En particulier, 'newbar' dans str (e) code> ressemble à un bogue en attente de se produire, d'autant plus que ce type de code doit être dans chaque implémentation remplacée de
get_fields code>. Par souci de maintenance future de ce code, je recommanderais sérieusement une approche plus propre.
Hm, oui, mais je ne peux pas changer d'original get_fields code> méthode. Il vient de la bibliothèque externe.
Je vois. Ce n'était pas clair à partir de votre exemple car foobar code>, le premier à définir
get_fields code>, utilise déjà votre métaclasse, il était donc raisonnable de supposer que
foobar code >, et l'ensemble de l'interface
get_fields code>, vous a été défini par vous.
Alors, est la métaclasse sous votre contrôle? Si tel est le cas, je pense que je peux modifier ma réponse au travail sans changer la signature de get_fields code>.
Peut-être que je devrais fournir un lien direct vers le code dans TASTYPIE < / a>.
Ou ... vous pouvez remplacer l'essai / à l'exception de la logique avec moi = newbar si "newbar" dans les globaux () sinon CLS code> puis appelle
super code> avec
super ( Moi, CLS) .get_fields () code>. Toujours un peu piraté, mais plus simple que ma proposition, et raisonnablement facile à suivre.
J'ai mis à jour ma réponse pour utiliser une troisième solution, qui doit simplement rechercher newbar code> dans
CLS .__ MRO __ code>. Celui-ci semble le moins moche - pas de bruit avec
global code> sous quelque forme que ce soit - mais il nécessite toujours une recherche à base de chaînes via MRO.
Je sais que la question est spécifique à Python 2.7, cependant, pour ceux qui utilisent Python 3.6, vous pouvez simplement appeler Super () code>.
class NewBar(FooBar):
@classmethod
def get_fields(cls):
super().get_fields()
...