Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Truth value of empty set

I am interested in the truth value of Python sets like {'a', 'b'}, or the empty set set() (which is not the same as the empty dictionary {}). In particular, I would like to know whether bool(my_set) is False if and only if the set my_set is empty.

Ignoring primitive (such as numerals) as well as user-defined types, https://docs.python.org/3/library/stdtypes.html#truth says:

The following values are considered false:

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

All other values are considered true

According to https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range, a set is not a sequence (it is unordered, its elements do not have indices, etc.):

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

And, according to https://docs.python.org/3/library/stdtypes.html#mapping-types-dict,

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

So, as far as I understand, the set type is not a type that can ever be False. However, when I try, bool(set()) evaluates to False.

Questions:

  • Is this a documentation problem, or am I getting something wrong?
  • Is the empty set the only set whose truth value is False?
like image 508
Peter Thomassen Avatar asked Jun 28 '17 22:06

Peter Thomassen


People also ask

What is the value of an empty set?

An empty set is a finite set since its cardinality is defined and is equal to 0.

Is empty set True or false?

Given statement is true i.e. an empty set is a subset of every set.

What is the formula of empty set?

In symbols, we write X ∩ ∅ = ∅. The union of any set with the empty set is the set we started with. This is because there are no elements in the empty set, and so we are not adding any elements to the other set when we form the union. In symbols, we write X U ∅ = X.

What is the truth value of 0?

In classical logic, with its intended semantics, the truth values are true (denoted by 1 or the verum ⊤), and untrue or false (denoted by 0 or the falsum ⊥); that is, classical logic is a two-valued logic. This set of two values is also called the Boolean domain.


1 Answers

After looking at the source code for CPython, I would guess this is a documentation error, however, it could be implementation dependent and therefore would be a good issue to raise on the Python bug tracker.

Specifically, object.c defines the truth value of an item as follows:

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

We can clearly see that the value is value would be always true if it is not a boolean type, None, a sequence, or a mapping type, which would require tp_as_sequence or tp_as_mapping to be set.

Fortunately, looking at setobject.c shows that sets do implement tp_as_sequence, suggesting the documentation seems to be 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 also implement tp_as_sequence, so it seems that although it is not a sequence type, it sequence-like, enough to be truthy.

In my opionion, the documentation should clarify this: mapping-like types, or sequence-like types will be truthy dependent on their length.

Edit As user2357112 correctly points out, tp_as_sequence and tp_as_mapping do not mean the type is a sequence or a map. For example, dict implements tp_as_sequence, and list implements tp_as_mapping.

like image 98
Alexander Huszagh Avatar answered Sep 19 '22 07:09

Alexander Huszagh