del and sets proposal

L

Larry Bates

You can do the following:

a = [1,2,3,4,5]
del a[0]

and

a = {1:'1', 2: '2', 3: '3', 4:'4', 5:'5'}
del a[1]

why doesn't it work the same for sets (particularly since sets are based on a
dictionary)?

a = set([1,2,3,4,5])
del a[1]

Yes I know that sets have a remove method (like lists), but since dictionaries
don't have a remove method, shouldn't sets behave like more like dictionaries
and less like lists? IMHO del for sets is quite intuitive. I guess it is too
late to change now.

-Larry
 
C

Chris Rebert

You can do the following:

a = [1,2,3,4,5]
del a[0]

and

a = {1:'1', 2: '2', 3: '3', 4:'4', 5:'5'}
del a[1]

why doesn't it work the same for sets (particularly since sets are based on
a dictionary)?

a = set([1,2,3,4,5])
del a[1]

Sets don't support subscripting, so if you can't go
'a_set[something]', why would you expect to be able to be able to
'del' such an expression? What would the subscription even mean
without the 'del'? It doesn't make sense and would just be
inconsistent.
Yes I know that sets have a remove method (like lists), but since
dictionaries don't have a remove method, shouldn't sets behave like more
like dictionaries and less like lists? IMHO del for sets is quite

No, sets are a datatype unto themselves. They are based on
dictionaries internally (at least in CPython), but that's an
implemention detail to be hidden, not emphasized.
intuitive. I guess it is too late to change now.

Most likely.

Cheers,
Chris
 
J

Jon Clements

You can do the following:

a = [1,2,3,4,5]
del a[0]

and

a = {1:'1', 2: '2', 3: '3', 4:'4', 5:'5'}
del a[1]

why doesn't it work the same for sets (particularly since sets are based on a
dictionary)?

a = set([1,2,3,4,5])
del a[1]

Yes I know that sets have a remove method (like lists), but since dictionaries
don't have a remove method, shouldn't sets behave like more like dictionaries
and less like lists?  IMHO del for sets is quite intuitive.  I guess it is too
late to change now.

-Larry
a = set( range(5) )
a[0]

Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
a[0]
TypeError: 'set' object is unindexable

No point it needing to be indexable either.

It's also worth noting that removing an object from a container
(.remove) is different than proposing the object goes to GC (del...)

Have to disagree that del[] on a set makes any sense.

Tired, and it's late, so probably typing rubbish, but felt okay when I
started reading the group :)

Jon.
 
M

Marc 'BlackJack' Rintsch

It's also worth noting that removing an object from a container
(.remove) is different than proposing the object goes to GC (del...)

``del`` doesn't propose that the object goes to GC, at least not more
then a `remove()` method does. Just like `remove()` ``del`` only removes
references to objects. Always.

Ciao,
Marc 'BlackJack' Rintsch
 
B

bearophileHUGS

Chris Rebert:
No, sets are a datatype unto themselves. They are based on
dictionaries internally (at least in CPython), but that's an
implemention detail to be hidden, not emphasized.

Later Hettinger has simplified their code, making them use less memory
(and be a little faster too, I think) :)

Bye,
bearophile
 
M

Marc 'BlackJack' Rintsch

a = set([1,2,3,4,5])
del a[1]

Sets don't support subscripting, so if you can't go 'a_set[something]',
why would you expect to be able to be able to 'del' such an expression?
What would the subscription even mean without the 'del'? It doesn't make
sense and would just be inconsistent.

Then add subscription access too. By aliasing `__getitem__()` to
`__contains__()`. And `__setitem__()` could be implemented to add or
remove objects by assigning truth values. So hypothetically:
a = set([1, 2, 3])
a[1] True
a[4] False
a[2] = False
a set([1, 3])
a[4] = True
a set([1, 3, 4])
del a[1]
a
set([3, 4])

I wouldn't want that addition to `set`\s but at least it can be
implemented without introducing inconsistencies.

Ciao,
Marc 'BlackJack' Rintsch
 
L

Larry Bates

Chris said:
You can do the following:

a = [1,2,3,4,5]
del a[0]

and

a = {1:'1', 2: '2', 3: '3', 4:'4', 5:'5'}
del a[1]

why doesn't it work the same for sets (particularly since sets are based on
a dictionary)?

a = set([1,2,3,4,5])
del a[1]

Sets don't support subscripting, so if you can't go
'a_set[something]', why would you expect to be able to be able to
'del' such an expression? What would the subscription even mean
without the 'del'? It doesn't make sense and would just be
inconsistent.
Yes I know that sets have a remove method (like lists), but since
dictionaries don't have a remove method, shouldn't sets behave like more
like dictionaries and less like lists? IMHO del for sets is quite

No, sets are a datatype unto themselves. They are based on
dictionaries internally (at least in CPython), but that's an
implemention detail to be hidden, not emphasized.
intuitive. I guess it is too late to change now.

Most likely.

Cheers,
Chris

I believe that the fact that Sets don't support indexing is an implementation
artifact that is due to the FACT that their underlying implementation is based
on dictionaries (a good choice in my opinion). One could just as easily have
implemented (but then they would not have performed so well) Sets as an ordered
list of unique values and have provided indexing capabilities (but I can't quite
think of a use case for such an animal right now).

I didn't mean to imply that del a[1] would delete the first thing in the set,
but rather the item with a value of 1. Just as when we use it on a dictionary:

del a[1]

doesn't mean delete the first dictionary entry but rather delete the entry in
the object with a value of 1, which IMHO would be perfectly logical for a set
(which is why I started this discussion). There is no ambiguity because sets,
like dictionaries, require uniqueness.

Maybe dictionaries should have had a .remove method then things would be more
consistent?

-Larry
 
G

George Sakkis

You can do the following:

a = [1,2,3,4,5]
del a[0]

and

a = {1:'1', 2: '2', 3: '3', 4:'4', 5:'5'}
del a[1]

why doesn't it work the same for sets (particularly since sets are based on a
dictionary)?

a = set([1,2,3,4,5])
del a[1]

Yes I know that sets have a remove method (like lists), but since dictionaries
don't have a remove method, shouldn't sets behave like more like dictionaries
and less like lists?  IMHO del for sets is quite intuitive.  I guess it is too
late to change now.

Funny, I would welcome a change in the opposite direction: drop
completely the "del a" syntax from the language and use an explicit
(non-special) method name, e.g. a.delete(i) or a.remove(i). Having
some functionality exposed through methods and some through function
builtins (e.g. len()) is more than enough; having a third way through
the del statement is unnecessarily perl-ish.

George
 
C

Carl Banks

a = set([1,2,3,4,5])
del a[1]
Sets don't support subscripting, so if you can't go 'a_set[something]',
why would you expect to be able to be able to 'del' such an expression?
What would the subscription even mean without the 'del'? It doesn't make
sense and would just be inconsistent.

Then add subscription access too.  By aliasing `__getitem__()` to
`__contains__()`.  And `__setitem__()` could be implemented to add or
remove objects by assigning truth values.  So hypothetically:
a = set([1, 2, 3])
a[1] True
a[4] False
a[2] = False
a set([1, 3])
a[4] = True
a set([1, 3, 4])
del a[1]
a

set([3, 4])

I wouldn't want that addition to `set`\s but at least it can be
implemented without introducing inconsistencies.


If set behaved that way then "del a[1]" wouldn't behave like del
anymore. Normally, "del whatever" means that you can no longer use
"whatever"; in this proposal you can.


Carl Banks
 
C

Carl Banks

I didn't mean to imply that del a[1] would delete the first thing in the set,
but rather the item with a value of 1.  Just as when we use it on a dictionary:

del a[1]

doesn't mean delete the first dictionary entry but rather delete the entry in
the object with a value of 1, which IMHO would be perfectly logical for a set
(which is why I started this discussion).


It's not logical at all. In all current uses of del, the thing that
follows del is a valid expression. With sets, that's not the case.


Carl Banks
 
S

Steven D'Aprano

I didn't mean to imply that del a[1] would delete the first thing in
the set, but rather the item with a value of 1.  Just as when we use it
on a dictionary:

del a[1]

doesn't mean delete the first dictionary entry but rather delete the
entry in the object with a value of 1, which IMHO would be perfectly
logical for a set (which is why I started this discussion).


It's not logical at all. In all current uses of del, the thing that
follows del is a valid expression. With sets, that's not the case.


I think Larry is suggesting that elements of sets should be removed in
the same way that keys of dictionaries are removed:

d = {57: "foo"}
s = set([57])


He's suggesting that del s[57] should work just like del d[57] works.

The fact that sets don't have a __getitem__ method doesn't mean that they
couldn't have a __delitem__ method:

class DelSet(set):
def __delitem__(self, element):
self.remove(element)

s = DelSet([1, 2, 3, 4, 5])
s DelSet([1, 2, 3, 4, 5])
del s[4]
del s[5]
s
DelSet([1, 2, 3])
 
B

bearophileHUGS

Steven D'Aprano:
Personally, I'd rather see dictionaries grow methods like
symmetric_difference, union, etc. than worry about whether you use del or
remove to remove elements from a set.

I have functions for all those operations, so I think they can be
useful, but in practice I don't use them often. I think it's a matter
of keeping data structures separated in the mind.

Another problem is that with those operations you have to find a way
to manage values too, are they part of the uniqueness, etc? So there
can be different semantics of a single operation, and this may lead to
people that have a wrong image model of the purpose of some of those
methods.

Bye,
bearophile
 
M

Marc 'BlackJack' Rintsch

Then add subscription access too.  By aliasing `__getitem__()` to
`__contains__()`.  And `__setitem__()` could be implemented to add or
remove objects by assigning truth values.  So hypothetically:
a = set([1, 2, 3])
a[1] True
False
a[2] = False
a set([1, 3])
a[4] = True
a set([1, 3, 4])
del a[1]
a

set([3, 4])

I wouldn't want that addition to `set`\s but at least it can be
implemented without introducing inconsistencies.


If set behaved that way then "del a[1]" wouldn't behave like del
anymore. Normally, "del whatever" means that you can no longer use
"whatever"; in this proposal you can.

Then there should be no ``del`` for `collections.defaultdict`:

In [169]: from collections import defaultdict

In [170]: d = defaultdict(int)

In [171]: d[42]
Out[171]: 0

In [172]: del d[42]

In [173]: d[42]
Out[173]: 0

Ciao,
Marc 'BlackJack' Rintsch
 
B

Bruno Desthuilliers

Larry Bates a écrit :
You can do the following:

a = [1,2,3,4,5]
del a[0]

and

a = {1:'1', 2: '2', 3: '3', 4:'4', 5:'5'}
del a[1]

why doesn't it work the same for sets (particularly since sets are based
on a dictionary)?

a = set([1,2,3,4,5])
del a[1]
>
Yes I know that sets have a remove method (like lists), but since
dictionaries don't have a remove method, shouldn't sets behave like more
like dictionaries and less like lists? IMHO del for sets is quite
intuitive.

For lists, del a[x] means 'remove item at index x'. For dicts, del a[x]
means 'remove key:value pair which key is x'. In both cases, del a[x] is
meaningful because a[x] is meaningful. Sets are neither ordered nor
indexed, and can't be subscripted. So "del aset[x]" is IMHO as
meaningless as 'aset[x]' is. Using this syntax for an operation which
semantic is the same as alist.remove(x) would be at best inconsistent
and confusing.
 
S

Steven D'Aprano

Yes I know that sets have a remove method (like lists), but since
dictionaries don't have a remove method, shouldn't sets behave like
more like dictionaries and less like lists? IMHO del for sets is quite
intuitive.

For lists, del a[x] means 'remove item at index x'. For dicts, del a[x]
means 'remove key:value pair which key is x'. In both cases, del a[x] is
meaningful because a[x] is meaningful. Sets are neither ordered nor
indexed, and can't be subscripted. So "del aset[x]" is IMHO as
meaningless as 'aset[x]' is. Using this syntax for an operation which
semantic is the same as alist.remove(x) would be at best inconsistent
and confusing.

Consider the mutable built-in collections set, dict and list, and how
they remove elements:

aset.remove(x)
alist.remove(x)
del adict[x]

Would it really be "confusing" if sets used the same interface as dicts
use? I don't think so. What else could "del aset[x]" mean other than
"delete element x"?

Lists are the odd one out, because del alist[x] is used to remove the
element at position x, rather than removing an element x. But because
sets are unordered, there's no ambiguity between element x and the
element at position x. In that regard, sets are just like dicts, and it
is a perfectly reasonable position to take that hypothetically sets could
use "del aset[x]" instead of "aset.remove(x)".

But on the other hand, if you can write "del aset[x]", why can't you
write "y = aset[x]" or "aset[x] = z"? Neither of these seem useful or
sensible, although at a stretch we could make "y = aset[x]" equivalent to
"y = x in aset".

Although there's no technical reason why sets can't have a __delitem__
method but no __getitem__ and __setitem__ methods, for consistency it
does seem rather unusual.

All this may seem academic, but consider the Bag (Multiset) data type.
With a Bag, you need to have two commands: "remove element x entirely",
and "remove one copy of element x only". To my mind, the natural API for
that is:

del abag[x] # remove element x entirely
abag.remove(x) # remove one copy of element x only
 
L

Lawrence D'Oliveiro

Steven D'Aprano said:
Would it really be "confusing" if sets used the same interface as dicts
use? I don't think so. What else could "del aset[x]" mean other than
"delete element x"?

Yes, but "x" in what sense? In dicts it's a key, in sets, shouldn't it also
be a key and not a value?

Sets have no keys, only values. One might suggest assignment of keys, à la
array indexes, but that means assigning an ordering to the values, whereas
sets are explicitly unordered.
 
S

Steven D'Aprano

Steven D'Aprano said:
Would it really be "confusing" if sets used the same interface as dicts
use? I don't think so. What else could "del aset[x]" mean other than
"delete element x"?

Yes, but "x" in what sense?

The only sense possible.

If I wrote aset.remove(x) would you ask "what's x, a key or a value?" No
of course you wouldn't, because the question is nonsense for sets. The
same goes for "x in aset", "aset.add(x)" and any other set method that
takes an element as an argument. Why are you singling out del for this
pretend confusion?

In dicts it's a key, in sets, shouldn't it
also be a key and not a value?

That question isn't even meaningful. Sets have elements. The semantics of
set elements is closer to dictionary keys than to dictionary values:

x in adict # is key x in dictionary?
x in aset # is element x in set?

and an early implementation of Python sets used dictionaries, where the
elements where stored as keys, not values. It makes no sense to treat set
elements as if they were analogous to dict values.

Sets have no keys, only values. One might suggest assignment of keys, à
la array indexes, but that means assigning an ordering to the values,
whereas sets are explicitly unordered.

Why on earth should "del aset[x]" imply that sets are ordered? Dicts
aren't ordered. You don't find people going "wibble wibble wibble, I
don't understand del adict[x] because dicts aren't ordered, what could it
mean???"
 
B

Bruno Desthuilliers

Steven D'Aprano a écrit :
Yes I know that sets have a remove method (like lists), but since
dictionaries don't have a remove method, shouldn't sets behave like
more like dictionaries and less like lists? IMHO del for sets is quite
intuitive.
For lists, del a[x] means 'remove item at index x'. For dicts, del a[x]
means 'remove key:value pair which key is x'. In both cases, del a[x] is
meaningful because a[x] is meaningful. Sets are neither ordered nor
indexed, and can't be subscripted. So "del aset[x]" is IMHO as
meaningless as 'aset[x]' is. Using this syntax for an operation which
semantic is the same as alist.remove(x) would be at best inconsistent
and confusing.

Consider the mutable built-in collections set, dict and list, and how
they remove elements:

aset.remove(x)
alist.remove(x)
del adict[x]

This last one doesn't remove the key,value pair(s) where *the value* is
x, it removes the key,value pair where the *key* is x - which is
semantically very different, just like alist.remove(x) is very different
from del alist[x].
Would it really be "confusing" if sets used the same interface as dicts
use? I don't think so.

I do. In both dict.__delitem__ and list.__delitem__, the argument is an
index (whether arbitrary key or positional index), not the value of the
element to remove. wrt/ consistency, i'd rather have dict growing a
remove(value) method with same semantic as list.remove and set.remove
than abuse subscript syntax to duplicate an existing API which has a
very different semantic.
What else could "del aset[x]" mean

As far as I'm concerned, since sets are not subscriptables, del aset[x]
just can't have any meaning.
other than
"delete element x"?

Going this way, 'del adict[x]' should mean 'remove key,value pair(s)
where value is x' and 'del alist[x]' should be an alias for alist.remove(x).

Lists are the odd one out, because del alist[x] is used to remove the
element at position x, rather than removing an element x.

Nope. It's perfectly consistent with dicts, where del adict[x] is used
to remove element associated to key x, not to remove element with value
x. Lists and dicts are both indexed collections, list being indexed by
position and dicts by key. sets are not indexed.

(snip remaining - I could only keep on repeating the same thing).
 
B

Bruno Desthuilliers

Steven D'Aprano a écrit :
Steven D'Aprano said:
Would it really be "confusing" if sets used the same interface as dicts
use? I don't think so. What else could "del aset[x]" mean other than
"delete element x"?
Yes, but "x" in what sense?

The only sense possible.

If I wrote aset.remove(x) would you ask "what's x, a key or a value?" No
of course you wouldn't, because the question is nonsense for sets.

And also because the semantic of 'remove' is already defined for lists.
The
same goes for "x in aset", "aset.add(x)" and any other set method that
takes an element as an argument. Why are you singling out del for this
pretend confusion?



That question isn't even meaningful. Sets have elements. The semantics of
set elements is closer to dictionary keys than to dictionary values:

x in adict # is key x in dictionary?

This is a pragmatic design choice - just like the fact that default
iteration over dicts is made on keys, not values - due to the most
frequent use case. FWIW, this has been debated quite a few times here.
x in aset # is element x in set?
and an early implementation of Python sets used dictionaries,

And this is only an implementation detail.
where the
elements where stored as keys, not values. It makes no sense to treat set
elements as if they were analogous to dict values.

Would it make sense to treat them as if they where list values ?-)
Sets have no keys, only values. One might suggest assignment of keys, à
la array indexes, but that means assigning an ordering to the values,
whereas sets are explicitly unordered.

Why on earth should "del aset[x]" imply that sets are ordered? Dicts
aren't ordered. You don't find people going "wibble wibble wibble, I
don't understand del adict[x] because dicts aren't ordered, what could it
mean???"

s/ordered/indexed/, and it makes perfect sense. Dicts and lists are
indexed, sets are not.
 
A

Aaron \Castironpi\ Brady

Bruno said:
Steven D'Aprano a écrit :
On Sat, 04 Oct 2008 18:36:28 +0200, Bruno Desthuilliers wrote:

Lists are the odd one out, because del alist[x] is used to remove the
element at position x, rather than removing an element x.

Nope. It's perfectly consistent with dicts, where del adict[x] is used
to remove element associated to key x, not to remove element with value
x. Lists and dicts are both indexed collections, list being indexed by
position and dicts by key. sets are not indexed.

(snip remaining - I could only keep on repeating the same thing).

Which one has seniority? It's somewhat arbitrary which of 'pop' and
'remove' have which meanings in lists. You can 'remove' on index or
value in lists, key or value in dicts, and only value in sets.

I agree that you don't pass an 'index' to 'del' in dicts, you pass a
key. Does the OP also hold that dicts should grow a 'remove' method to
remove a value?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top