TL;DR If people really object to & doing double-duty as bitwise-AND and chaining, there's always && as a possibility.
On Tue, Jun 27, 2017 at 12:47:40AM -0700, David Mertz wrote: > > - keep the existing __and__ and __rand__ behaviour; > > - if they are not defined, and both operands x, y are iterable, > > return chain(x, y); > > > > I understand. But it invites confusion about just what the `&` operator > will do for a given iterable. With operator overloading, that's a risk for any operator, and true for everything except literals. What will `x * y` do? How about `y * x`? They're not even guarenteed to call the same dunder method. But this is a problem in theory far more than in practice. In practice, you know what types you are expecting, and if you don't get them, you either explicitly raise an exception, or wait for something to fail. "Consenting adults" applies, and we often put responsibility back on the caller to do the right thing. If you expect to use & on iterable arguments, it is reasonable to put the responsibility on the caller to only provide "sensible" iterables, not something wacky like an infinite generator (unless your code is explicitly documented as able to handle them) or one that overrides __(r)and__. Or you could check for it yourself, if you don't trust the argument: if hasattr(arg, '__and__') or hasattr(arg, '__rand__'): raise Something But that strikes me as overkill. You don't normally check for dunders before using an operator, and we already have operators that can return different types depending on the operands: % can mean modulo division or string interpolation * can mean sequence repetition or numeric multiplication + can mean numeric addition or sequence concatenation Why is & can mean ierable chaining or bitwise-AND uniquely confusing? > For NumPy itself, you don't really want to > spell `chain(a, b)` so much. But you CAN, they are iterables. The > idiomatic way is: > > >>> np.concat((a,b)) > array([1, 2, 3, 4, 5, 6]) That's not really chaining, per say -- it is concatenating two arrays to create a third array. (Probably by copying the array elements.) If you wanted to chain a numpy array, you would either use itertools.chain directly, or call iter(myarray) before using the & operator. > However, for "any old iterable" it feels very strange to need to inspect > the .__and__() and .__rand__ () methods of the things on both sides before > you know WHAT operator it is. Do you inspect the dunder methods of objects before calling + or * or & currently? Why would you need to start now? Since there's no way of peering into an object's dunder methods and seeing what they do (short of reading the source code), you always have an element of trust and hope whenever you call an operator on anything but a literal. > Maybe if you are confident a and b are exactly NumPy arrays it is obvious, > but what about: > > from some_array_library import a > from other_array_library import b > > What do you think `a & b` will do under your proposal? Yes, I understand > it's deterministic... but it's far from *obvious*. It's not "obvious" now, since a and b can do anything they like in their dunder methods. They could even inspect the call stack from __next__ and if they see "chain" in the stack, erase your hard drive. Does that mean we don't dare call chain(a, b)? I don't think this proposal adds any new risk. All the risk already exists as soon as you allow method overloading. All we're doing is saying is "try the method overloading first, and if that isn't supported, try iterable chaining second before raising TypeError". > This isn't even doing > something pathological like defining both `.__iter__()` and `.__and__()` on > the same class... which honestly, isn't even all that pathological; I can > imagine real-world use cases. Indeed -- numpy arrays probably do that, as do sets and frozensets. I didn't say it was pathological, I said it was uncommon. > I think that chaining iterators is common enough and important enough in > > Python 3 to deserve an operator. While lists are still important, a lot > > of things which were lists are now lazily generated iterators, and we > > often need to concatenate them. itertools.chain() is less convenient > > than it should be. > > > > I actually completely agree! I just wish I could think of a good character > that doesn't have some very different meaning in other well-known contexts > (even among iterables). There's always && for iterator chaining. -- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/