Yes, sets and dicts are very similar. Dicts were the original data structure in python2. You could implement a set as just the keys of a dict (no values). So the current set implementation exposes some of the underlying dict machinery with KeyError.
List data isn’t stored by key/hash. Removing an element by value requires searching the list and matching a particular value.
The documentation on the methods describe the errors might arise. For sets, remove() and pop() may throw a KeyError. ValueError should not be possible.
Set Types
...
remove(elem)
Remove element elem from the set. Raises KeyError if elem is not contained in the set.
...
pop()
Remove and return an arbitrary element from the set. Raises KeyError if the set is empty.
Whereas for lists, ValueError can be generated.
Lists
...
3. remove() raises ValueError when x is not found in s.
Essentially. They’re very much like dicts whose values are also the
keys. SO it has the same behaviours.
Changing to ValueError now (versus in the distant past at the design
phase) would break any code using KeyError to detect an attempt to
remove an element which was not present.
And because sets are a lot like dicts, people (waves ahnds vaguely)
would probably rather get a KeyError anyway.
A ValueError tends to mean an unsuitable value. A KeyError or IndexError
means a value which was not present. And IndexError is for indices -
generally a sequence such as the int index on a list - and KeyError is
for other things.
We’re not going to change the exception raised by sets. As Serhiy says,
changing the exception would break thousands of programs that expect
set.remove to raise KeyError.
If you want to remove an item from a list or a set, and you’re not sure
which, you can write this:
# collection might be a list, or a set
try:
collection.remove(item)
except (KeyError, ValueError):
# item not found
...