41 votes

Valeur de vérité de l'ensemble vide

Je suis intéressé par la valeur de vérité de Python définit comme {'a', 'b'}, ou l'ensemble vide set() (ce qui n'est pas le même que le dictionnaire vide {}). En particulier, je voudrais savoir si bool(my_set) est False si et seulement si l'ensemble my_set est vide.

Ignorant primitive (comme les chiffres) ainsi que les types définis par l'utilisateur, https://docs.python.org/3/library/stdtypes.html#truth dit:

Les valeurs suivantes sont considérées comme fausses:

  • [...]
  • toute séquence vide, par exemple, '', (), [].
  • tout vide de cartographie, par exemple, {}.
  • [...]

Toutes les autres valeurs sont considérées comme de vraies

Selon https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-rangeun ensemble n'est pas une séquence (il n'est pas ordonné, ses éléments n'ont pas d'indices, etc.):

Il existe trois principaux types de séquences: les listes, les tuples, et la gamme des objets.

Et, selon https://docs.python.org/3/library/stdtypes.html#mapping-types-dict,

Il n'y a actuellement qu'une seule norme de cartographie type, le dictionnaire.

Donc, comme je le comprends, le type de jeu n'est pas un type qui ne peut jamais être False. Cependant, lorsque j'essaie, bool(set()) évalue False.

Questions:

  • Est-ce une documentation problème, ou suis-je quelque chose de mal?
  • Est l'ensemble vide, le seul jeu dont la valeur de vérité est - False?

30voto

Alexander Huszagh Points 6661

Après avoir regardé le code source Disponible, je pense que c'est une erreur de documentation, cependant, il pourrait être mise en œuvre dépendante et donc serait une bonne question à poser au Python bug tracker.

Plus précisément, l'objet.c définit la valeur de vérité d'un élément comme suit:

int
PyObject_IsTrue(PyObject *v)
{
    Py_ssize_t res;
    if (v == Py_True)
        return 1;
    if (v == Py_False)
        return 0;
    if (v == Py_None)
        return 0;
    else if (v->ob_type->tp_as_number != NULL &&
             v->ob_type->tp_as_number->nb_bool != NULL)
        res = (*v->ob_type->tp_as_number->nb_bool)(v);
    else if (v->ob_type->tp_as_mapping != NULL &&
             v->ob_type->tp_as_mapping->mp_length != NULL)
        res = (*v->ob_type->tp_as_mapping->mp_length)(v);
    else if (v->ob_type->tp_as_sequence != NULL &&
             v->ob_type->tp_as_sequence->sq_length != NULL)
        res = (*v->ob_type->tp_as_sequence->sq_length)(v);
    else
        return 1;
    /* if it is negative, it should be either -1 or -2 */
    return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int);
}

Nous pouvons clairement voir que la valeur est la valeur serait toujours vraie si elle n'est pas de type booléen, Aucun, une séquence ou un type de mapping, qui aurait besoin d'tp_as_sequence ou tp_as_mapping à définir.

Heureusement, en regardant setobject.c montre que les ensembles de mettre en œuvre tp_as_sequence, ce qui suggère la documentation semble être incorrect.

PyTypeObject PySet_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "set",                              /* tp_name */
    sizeof(PySetObject),                /* tp_basicsize */
    0,                                  /* tp_itemsize */
    /* methods */
    (destructor)set_dealloc,            /* tp_dealloc */
    0,                                  /* tp_print */
    0,                                  /* tp_getattr */
    0,                                  /* tp_setattr */
    0,                                  /* tp_reserved */
    (reprfunc)set_repr,                 /* tp_repr */
    &set_as_number,                     /* tp_as_number */
    &set_as_sequence,                   /* tp_as_sequence */
    0,                                  /* tp_as_mapping */
    /* ellipsed lines */
};

Dicts également de mettre en œuvre tp_as_sequence, il semble donc que, bien qu'il n'est pas un type de séquence, c'séquence-comme, assez pour être truthy.

À mon avis, la documentation devrait clarifier ce point:-cartographie tels que les types, ou l'ordre comme types de truthy dépend de leur longueur.

Modifier Comme user2357112 souligne à juste titre, tp_as_sequence et tp_as_mapping ne signifie pas que le type est une séquence ou d'une carte. Par exemple, dict implémente tp_as_sequence, et la liste implémente tp_as_mapping.

26voto

a_guest Points 5059

La documentation pour l' __bool__ indique que cette méthode est appelée pour la valeur de vérité de test et si elle n'est pas définie alors __len__ est évaluée:

Appelés à mettre en œuvre vérité le test de la valeur et de l'exploitation intégré bool(); [...] Lorsque cette méthode n'est pas définie, __len__() est appelée, si elle est définie, et l'objet est considérée comme vraie si son résultat est différent de zéro. Si une classe ne définit ni __len__() ni __bool__(), toutes ses instances sont considérées comme de vraies.

Cela vaut pour n'importe quel objet Python. Comme nous pouvons le voir set ne permet pas de définir une méthode __bool__:

>>> set.__bool__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'set' has no attribute '__bool__'

de sorte que la vérité de test retombe dans l' __len__:

>>> set.__len__
<slot wrapper '__len__' of 'set' objects>

Par conséquent, seul un ensemble vide (de longueur nulle) est considérée comme fausse.

La partie pour la valeur de vérité de test dans la documentation n'est pas complète à l'égard de cet aspect.

18voto

user2357112 Points 37737

Cette partie de la documentation est mal écrit, ou plutôt, mal entretenues. La clause suivante:

les instances de classes définies par l'utilisateur, si la classe définit un __bool__() ou __len__() méthode, lorsque cette méthode renvoie le nombre entier zéro ou une valeur booléenne False.

s'applique vraiment à toutes les classes définies par l'utilisateur, ou non, y compris set, dict, et même les types répertoriés dans toutes les autres clauses qui définissent __bool__ ou __len__). (En Python 2, None est faux, malgré ne pas avoir un __len__ ou Python 2 est l'équivalent de __bool__, mais cette exception est passé depuis Python 3.3.)

Je dis mal entretenues parce que cette section a été presque inchangé depuis au moins Python 1.4, et peut-être plus tôt. Il a été mis à jour pour l'ajout d' False et la suppression de séparer int/long des types, mais pas pour type/classe d'unification ou de l'introduction de jeux.

En arrière quand la cité de la clause a été écrit, classes définies par l'utilisateur et les types intégrés vraiment fait de se comporter différemment, et je ne pense pas intégré dans les types avaient vraiment __bool__ ou __len__ du temps.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X