On 11/29/2018 6:13 AM, E. Madison Bray wrote:
On Wed, Nov 28, 2018 at 8:54 PM Terry Reedy <tjre...@udel.edu> wrote:

The CPython map() implementation already carries this data on it as
"func" and "iters" members in its struct.  It's trivial to expose
those to Python as ".funcs" and ".iters" attributes.  Nothing
"special" about it.  However, that brings me to...

I will come back to this when you do.

https://docs.python.org/3/library/functions.html#map says
"map(function, iterable, ...)
      Return an iterator [...]"

The wording is intentional.  The fact that map is a class and the
iterator an instance of the class is a CPython implementation detail.
Another implementation could use the generator function equivalent given
in the Python 2 itertools doc, or a translation thereof.  I don't know
what pypy and other implementations do.  The fact that CPython itertools
callables are (now) C-coded classes instead Python-coded generator
functions, or C translations thereof (which is tricky) is for
performance and ease of maintenance.

Exactly how intentional is that wording though?

The use of 'iterator' is exactly intended, and the iterator protocol is *intentionally minimal*, with one iterator specific __next__ method and one boilerplate __iter__ method returning self. This is more minimal than some might like. An argument against the addition of length_hint and __length_hint__ was that it might be seen as extending at least the 'expected' iterator protocol. The docs were written to avoid this.

If it returns an
iterator it has to return *some object* that implements iteration in
the manner prescribed by map.

Generator functions could theoretically
allow attributes attached to them.  Roughly speaking:

def map(func, *iters):
     def map_inner():
         for args in zip(*iters):
             yield func(*args)

     gen = map_inner()
     gen.func = func
     gen.iters = iters

     return gen

As it happens this won't work in CPython since it does not allow
attribute assignment on generator objects.  Perhaps there's some good
reason for that, but AFAICT--though I may be missing a PEP or
something--this fact is not prescribed anywhere and is also particular
to CPython.

Instances of C-coded classes generally cannot be augmented. But set this issue aside.

 Point being, I don't think it's a massive leap or
imposition on any implementation to go from "Return an iterator [...]"
to "Return an iterator that has these attributes [...]"

Do you propose exposing the inner struct members of *all* C-coded iterators? (And would you propose that all Python-coded iterators should use public names for the equivalents?) Some subset thereof? (What choice rule?) Or only for map? If the latter, why do you consider map so special?

This is necessary because if I have a function that used to take, say,
a list as an argument, and it receives a `map` object, I now have to
be able to deal with map()s,

In both 2 and 3, the function has to deal with iterator inputs one way or another. In both 2 and 3, possible interator inputs includes maps passed as generator comprehensions, '(<expression with x> for x in iterable)'.

If a function is documented as requiring a list, or a sequence, or a
length object, it is a user bug to pass an iterator.  The only thing
special about map and filter as errors is the rebinding of the names
between Py2 and Py3, so that the same code may be good in 2.x and bad in
3.x.

It's not a user bug if you're porting a massive computer algebra
application that happens to use Python as its implementation language
(rather than inventing one from scratch) and your users don't need or
want to know too much about Python 2 vs Python 3.

As a former 'scientist who programs' I can understand the desire for ignorance of such details. As a Python core developer, I would say that if you want Sage to allow and cater to such ignorance, you have to either make Sage a '2 and 3' environment, without burdening Python 3, or make future Sage a strictly Python 3 environment (as many scientific stack packages are doing or planning to do).

...
That said, I regret bringing up Sage; I was using it as an example but
I think the point stands on its own.

Yes, the issues of hiding versus exposing implementation details, and that of saving versus deleting and, when needed, recreating 'redundant' information, are independent of Sage and 2 versus 3.

--
Terry Jan Reedy

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to