I accidentally replied only to Steven - sorry! - this is what I said, with a typo corrected:
> a_list_of_strings..lower()
>
> str.lower.(a_list_of_strings)
I much prefer this solution to any of the other things discussed so far. I wonder, though, would it be general enough to simply have this new '.' operator interact with __iter__, or would there have to be new magic methods like __veccall__, __vecgetattr__, etc? Would a single __vectorize__ magic method be enough?
For example, I would expect (1, 2, 3) .** 2 to evaluate as a tuple and [1, 2, 3] .** 2 to evaluate as a list, and some_generator() .** 2 to still be a generator.
If there were a __vectorize__(self, func) which returned the iterable result of applying func on each element of self:
class list:
def __vectorize__(self, func):
return [func(e) for e in self]
some_list .* other becomes some_list.__vectorize__(lambda e: e * 2)
some_string..lower() becomes some_string.__vectorize__(str.lower)
some_list..attr becomes some_list.__vectorize__(operator.__attrgetter__('attr'))
Perhaps there would be a better name for such a magic method, but I believe it would allow existing sequences to behave as one might expect, but not require each operator to require its own definition. I might also be over-complicating this, but I'm not sure how else to allow different sequences to give results of their same type.