空s的真值

2024-09-29 03:38:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我对Python集合的真值很感兴趣,比如{'a', 'b'},或者空集{}(这与空字典{}不同)。特别是,我想知道bool(my_set)是否是False当且仅当集合my_set为空时。在

忽略原语(如数字)和用户定义的类型,https://docs.python.org/3/library/stdtypes.html#truth表示:

The following values are considered false:

  • [...]
  • any empty sequence, for example, '', (), [].
  • any empty mapping, for example, {}.
  • [...]

All other values are considered true

根据https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range,集合不是序列(它是无序的,它的元素没有索引,等等):

There are three basic sequence types: lists, tuples, and range objects.

根据https://docs.python.org/3/library/stdtypes.html#mapping-types-dict

There is currently only one standard mapping type, the dictionary.

因此,据我所知,set类型不是可以是False的类型。但是,当我尝试时,bool(set())的计算结果是False。在

问题:

  • 这是文档问题,还是我搞错了什么?在
  • 空集是唯一的真值为False的集吗?在

Tags: httpsorgfalsedocs类型htmllibrarymapping
3条回答

在看过CPython的源代码之后,我想这是一个文档错误,但是,它可能与实现相关,因此在Python bug跟踪器上提出是一个很好的问题。在

具体来说,object.c定义项的真值如下:

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);
}

我们可以清楚地看到,如果value is value不是布尔类型、None、sequence或映射类型,那么它将始终为true,这需要设置tp_as_sequence或tp_as_映射。在

幸运的是,查看setobject.c可以看出集合确实实现了tp_as_序列,这表明文档似乎不正确。在

^{pr2}$

Dicts还将tp_实现为序列,因此看起来虽然它不是序列类型,但它类似于序列,这足够真实。在

在我看来,文档应该澄清这一点:映射类类型或类似序列的类型将是真实的,这取决于它们的长度。在

编辑正如user2357112正确指出的,tp_as_sequence和{}并不意味着类型是序列或映射。例如,dict实现tp_as_sequence,list实现tp_as_mapping。在

^{}的文档指出,调用此方法进行真值测试,如果未定义该方法,则对^{}求值:

Called to implement truth value testing and the built-in operation bool(); [...] When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__() nor __bool__(), all its instances are considered true.

这适用于任何Python对象。如我们所见,set没有定义方法__bool__

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

因此,真实性检验取决于__len__

^{pr2}$

因此,只有空集(零长度)被认为是错误的。在

文档中truth value testing的部分在这方面不完整。在

这部分文档写得不好,或者更确切地说,维护不善。以下条款:

instances of user-defined classes, if the class defines a __bool__() or __len__() method, when that method returns the integer zero or bool value False.

真正适用于所有类,无论是否用户定义,包括setdict,甚至所有其他子句中列出的类型(所有这些子句都定义__bool__或{})。(在Python2中,None是错误的,尽管没有__len__或python2的__bool__的等价物,但该异常是gone since Python 3.3。)

我说维护得不好是因为这个部分至少从Python 1.4开始就几乎没有变化,也许更早。它的更新是为了添加False和删除单独的int/long类型,但不是为了类型/类的统一或集合的引入。在

在编写quoted子句时,用户定义的类和内置类型的行为确实不同,我不认为内置类型在当时实际上没有__bool__或{}。在

相关问题 更多 >