# \`list() - dict().items()\` returns \`set()\`?

**URL:** <https://discuss.python.org/t/list-dict-items-returns-set/16093>\
**Category:** Python Help\
**Created:** [May 31, 2022, 1:52am UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093 "2022-05-31T01:52:18Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![vainaixr](https://avatars.discourse-cdn.com/v4/letter/v/5f8ce5/32.png) [@vainaixr](https://discuss.python.org/u/vainaixr)\
**Post date:** [May 31, 2022, 1:52am UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093/1 "2022-05-31T01:52:18Z")

</div>

current scenario -

1. if we subtract an object of type `dict_items` from an object of type `list` then it returns a set
2. based on my inspection, there are only two types that one could subtract from a list, dict\_items, and dict\_keys.  
example,  
both,

```auto
[1] - dict({'a': 1}).items()

```

and,

```auto
[1] - dict({'a': 1}).keys()

```

give,

```auto
{1}

```

expected scenario -

1. this subtraction is made invalid, just like `list() - list()` or `list() - set()` is invalid.

note -  
similar pattern is also observed if we use a `str`, `tuple` instead of a `list`  
that is,

```auto
'abc' - dict({'a': 1}).keys()

```

gives the set,

```auto
{'b', 'c'}

```

I think this should be made invalid, just like, `'abc' - 'a'` is invalid.

---

<div class="post-metadata">

**Author:** ![steven.daprano](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steven.daprano/32/1083_2.png) [@steven.daprano](https://discuss.python.org/u/steven.daprano)\
**Post date:** [May 31, 2022, 2:17am UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093/2 "2022-05-31T02:17:40Z")

</div>

Welcome to the wonderful world of operator overloading!

When you use an operator, like `-`, both operands are checked to see if they support the operator with the other argument.

So when you do `mylist - mydict.items()`, the interpreter checks:

- Do lists support subtracting other objects? No.
- Do dict itemview objects support being subtracted from other objects? Yes.

And so the operation succeeds.

Dict itemview objects support a “set-like” interface, which includes subtraction, and so the subtraction succeeds.

Likewise for all the other examples. Keyview and itemview objects accept any sort of sequence or set as the other operand for set union, intersection, difference etc.

---

<div class="post-metadata">

**Author:** ![vainaixr](https://avatars.discourse-cdn.com/v4/letter/v/5f8ce5/32.png) [@vainaixr](https://discuss.python.org/u/vainaixr)\
**Post date:** [June 3, 2022, 3:37pm UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093/3 "2022-06-03T15:37:40Z")

</div>

but shouldn’t subtraction return some object that is a subset of the first argument, for example,

```auto
{1, 2, 3} - {1}

```

would give,

```auto
{2, 3}

```

which is a subset of `{1, 2, 3}`, but for `list() - dict().items()`, subtraction returns an object of a new type, shouldn’t it be a subset of the first argument, which is a `list()`, and a subset of a `list()` does not mean anything, as subtraction is not valid on a list, so the subtraction `list() - dict().items()` should also be invalid.

---

<div class="post-metadata">

**Author:** ![cameron](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cameron/32/2658_2.png) [@cameron](https://discuss.python.org/u/cameron)\
**Post date:** [June 3, 2022, 9:33pm UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093/4 "2022-06-03T21:33:24Z")

</div>

By via Discussions on [Python.org](http://Python.org) at 03Jun2022 15:48:

> but shouldn’t subtraction return some object that is a subset of the  
> first argument, for example,
> 
> ```auto
> {1, 2, 3} - {1}
> 
> ```
> 
> would give,
> 
> ```auto
> {2, 3}
> 
> ```
> 
> which is a subset of `{1, 2, 3}`, but for `list() - dict().items()`,  
> subtraction returns an object of a new type, shouldn’t it be a subset  
> of the first argument, which is a `list()`, and a subset of a `list()`  
> does not mean anything, as subtraction is not valid on a list, so the  
> subtraction `list() - dict().items()` should also be invalid.

Well, no.

The implementors of itemview wanted subtraction to be a meaningful idea.  
Since subtraction between lists is not supported (we could argue for  
days about what that should mean, if it were supported) they chose to  
use a set operation for subtraction. This has the advantage that it can  
be efficient, since a set membership test is O(1).

The result of a set operation is naturally a set.

Have a read of this:

> **[Built-in Types](https://docs.python.org/3/library/stdtypes.html#dict-views)**
>
> The following sections describe the standard types that are built into the interpreter. The principal built-in types are numerics, sequences, mappings, classes, instances and exceptions. Some colle...

which explains some of the rationale, and why the views are considered  
set-like, and thus the operations return sets.

If you think of subtraction as a function instead of an operator,  
consider that many functions return values of a different type from  
their operands. For a particular type there will be a suite of functions  
which return values in the same domain (same type), but also some  
functions which return values in a new domain, or of a different type.

You’ve got subtraction between a list and a dict item view. These are  
different types already. If another list is not a reasonable result (or,  
if not unreasonable, just not the _desired_ or _preferred_ kind of  
result), and the operation can’t really return another itemview (because  
such a thing is inherently a view of a dict), a “set” result is useful  
and reasonable. Particularly since it can immediately be used with other  
sets!

Cheers,  
Cameron Simpson [cs@cskk.id.au](mailto:cs@cskk.id.au)

---

<div class="post-metadata">

**Author:** ![steven.daprano](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steven.daprano/32/1083_2.png) [@steven.daprano](https://discuss.python.org/u/steven.daprano)\
**Post date:** [June 3, 2022, 11:37pm UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093/5 "2022-06-03T23:37:22Z")

</div>

Many operations coerce their arguments to a common type, which may not necessarily even be the type of either operand.

There is nothing wrong with an operator accepting objects by their interface, not their type, such as this:

```
(set-like object) - (any iterable) -> set
(any iterable) - (set-like object) -> set

```

Of course, any language that allows operator overloading has to come up with a rule for deciding which operand wins. Python’s rule is complex, and I may have some details wrong, but I believe it works like this:

- Each operator corresponds to a pair of dunder methods, a regular method and a “reflected” method; e.g. for subtraction they are ` __sub__ ` and ` __rsub__ `.
- If an object doesn’t support the operation at all, it should just not define those two dunders.
- If it supports the operation for only some arguments, it should return `NotImplemented` to signal that the object does not understand how to perform the operation.
- First object to return any other return result, or raise an exception, wins.
- The standard behaviour is to call the left-hand object’s ` __sub__ ` method first, and if that is missing or returns `NotImplemented`, try the right-hand object’s ` __rsub__ ` method.
- If both methods are missing or return `NotImplemented`, the default behaviour is to raise `TypeError`.

There are two exceptional cases:

- If both objects are the exact same type, then the reflected method isn’t tried.
- If the right-hand object is a subclass of the left-hand object, then its reflected method is tried first.

Comparison operators have a slightly different set of names for reflected dunders, e.g. ` __gt__ ` and ` __lt__ ` are reflections of each other.

---

<div class="post-metadata">

**Author:** ![vainaixr](https://avatars.discourse-cdn.com/v4/letter/v/5f8ce5/32.png) [@vainaixr](https://discuss.python.org/u/vainaixr)\
**Post date:** [June 4, 2022, 11:22am UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093/6 "2022-06-04T11:22:11Z")

</div>

shouldn’t even sets work here, that is,

```auto
[1] - {1}

```

should give,

```auto
set()

```

but instead it gives,

```auto
TypeError: unsupported operand type(s) for -: 'list' and 'set'

```

---

<div class="post-metadata">

**Author:** ![komoto48g](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/komoto48g/32/6978_2.png) [@komoto48g](https://discuss.python.org/u/komoto48g)\
**Post date:** [June 4, 2022, 1:48pm UTC](https://discuss.python.org/t/list-dict-items-returns-set/16093/7 "2022-06-04T13:48:39Z")

</div>

> [@steven.daprano](#):
>
> There is nothing wrong with an operator accepting objects by their interface, not their type, such as this:
> 
> ```auto
> (set-like object) - (any iterable) -> set
> (any iterable) - (set-like object) -> set
> 
> ```

I think @steven.daprano intended like,

```auto
(set-like *dict-view* object) - (any iterable) -> set
(any iterable) - (set-like *dict-view* object) -> set

```
