python / python/cpython

Resolution / determining of metaclass docs don't align with what really happens

Ouverte
#99,505 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

docs
Langage dominant
Python
Étoiles
77.2k
Forks
36k
Métriques de merge des PR
Métriques de PR en attente

Description

Documentation

I'm not 100% sure if this is an issue with the docs or the interpreter. But it's evident that the docs don't match what the interpreter does.

The docs say here:

The appropriate metaclass for a class definition is determined as follows:

  • if no bases and no explicit metaclass are given, then :func:type is used;
  • if an explicit metaclass is given and it is not an instance of
    :func:type, then it is used directly as the metaclass;
  • if an instance of :func:type is given as the explicit metaclass, or
    bases are defined, then the most derived metaclass is used.

The most derived metaclass is selected from the explicitly specified
metaclass (if any) and the metaclasses (i.e. type(cls)) of all specified
base classes. The most derived metaclass is one which is a subtype of all
of these candidate metaclasses. If none of the candidate metaclasses meets
that criterion, then the class definition will fail with TypeError.

So according to that, the metaclass of D in this code

class M1(type): pass
class M2(type): pass
class Mx(M1, M2): pass

class A1(metaclass=M1): pass
class A2(A1): pass

class B1(metaclass=M2): pass

class C1(metaclass=Mx): pass

class D(A2, B1, C1): pass

should be Mx as it's the most derived of all candidates (M1, M2, Mx). But instead the cpython exitis with

    class D(A2, B1, C1): pass
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

Note that class D(A2, C1, B1): pass works.

Some additional context:

As said above, I'm not even sure what the actually algorithm is that determines the implicit metaclass. From my experimentation, I assume it's:

  • If there's an explicit metaclass, it is checked to be a sub-class of the metaclass of each parent
  • If there's no explicit metaclass, the parents are checked from left to right:
    • When a new metaclass is encountered, it is checked to be a sub-class of the previous implicit metaclass and, if it is, set as the new implicit metaclass.
Linked PRs
  • gh-123349

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par la section sur les metaclasses dans Doc/reference/datamodel.rst et exécutez sous CPython les exemples fournis de définition de classes afin de comparer le comportement documenté et le comportement observé. Examinez le PR lié gh-123349 ainsi que l’issue historique référencée pour l’étude actuelle. La tâche est terminée lorsque le comportement de l’interpréteur et la documentation sont réconciliés avec une résolution claire.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
documentation
Type d'issue
Documentation
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
25/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.