[Python-ideas] Another attempt at a sum() alternative: the concatenation protocol

Sergey sergemp at mail.ru
Fri Jul 19 04:16:45 CEST 2013


On Jul 17, 2013 David Mertz:

>> Imagine a type, that somehow modifies items that it stores, removes
>> duplicates, or sorts them, or something else, e.g.:
>>   class aset(set):
>>       def __add__(self, other):
>>           return self|other
>>
>> Now we have a code:
>>   list_of_sets = [ aset(["item1","item2","item3"]) ] * 1000
>>   [...]
>>   for i in sum(list_of_sets, aset()):
>>       deal_with(i)
>>
>> If you replace `sum` with `chain` you get something like:
>>   for i in chain.from_iterable(list_of_sets):
>>       deal_with(i)
>>
>> Which works! (that's the worst part) but produces WRONG result!
> 
> In this example you can use:
> 
> aset(chain(*list_of_sets))
> 
> This gives the same answer with the same big-O runtime.

Sure, that's why I called it "error-prone" replacement.
When you have a code like:
>>   for i in sum(list_of_sets, aset()):
>>       deal_with(i)
You have pretty much no place for error.

Well, it would be much better, if it was just:
>>   for i in sum(list_of_sets):
>>       deal_with(i)
but for historical reasons we already have second parameter,
so we have to deal with it.

And now some newbie tries to use chain. So she does:
>>   for i in chain(list_of_sets):
>>       deal_with(i)
oops, does not work. Ah, missing star (you miss it yourself!)
>>   for i in chain(*list_of_sets):
>>       deal_with(i)
works, but incorrectly. Ok, let's hope that our newbie was careful
enough with tests and noticed, that it does not do what it should.
She reads the tutorial again, and notices that the example there was
like:
  all_elems = list(chain(*list_of_lists))
So she tries:
>>   for i in list(chain(*list_of_sets)):
>>       deal_with(i)
Nope, still wrong. Just in case she tries to remove a star, that she
don't understand anyway:
>>   for i in list(chain(list_of_sets)):
>>       deal_with(i)
Still no go. So after all these attempts she asks someone smart and
finally gets the correct code:
>>   for i in aset(chain(list_of_sets)):
>>       deal_with(i)

As I said, `chain` is a nice feature for smart people. But it is
neither good for beginners, nor obvious, nor it's good as a sum
replacement.

> It's possible to come up with more perverse customizations where
> this won't hold. But I think all of them involve redefining
> __add__ as something with little relation to it's normal meaning.
> Odd behavior in those cases is to be expected.

Hah. Easy. Even for commonly used type — for strings:
  str(chain(*list_of_strings))
it does not work.

So we have:

* chain(*list_of_something)
  may be correct or may be not

* something(chain(*list_of_something))
  may be correct or may be not

And technically it's easy to have a type, where both of those cases
are incorrect.



More information about the Python-ideas mailing list