[Python-ideas] Statements vs Expressions... why?

Cliff Wells cliff at develix.com
Sun Sep 14 10:36:55 CEST 2008


On Sun, 2008-09-14 at 01:25 -0700, Cliff Wells wrote:
> On Sun, 2008-09-14 at 08:36 +0100, Arnaud Delobelle wrote:
> > On 14 Sep 2008, at 07:36, Cliff Wells wrote:
> > 
> > > On Sun, 2008-09-14 at 07:23 +0100, Arnaud Delobelle wrote:
> > >> On 13 Sep 2008, at 23:17, Cliff Wells wrote:
> > >>
> > >>> On Sat, 2008-09-13 at 19:01 +0100, Arnaud Delobelle wrote:
> > >>>>
> > >>>> So what does:
> > >>>>
> > >>>> a = (if False: 1)
> > >>>>
> > >>>> evaluate to?
> > >>>
> > >>> That's a good question.  This is one of those areas where a  
> > >>> definition
> > >>> would need to be created.  My inclination is to say None (much  
> > >>> like a
> > >>> function with no return statement).
> > >>>
> > >>
> > >> Assuming the return value of "None", I go back to an example I gave
> > >> earlier:
> > >>
> > >>    factors = for x in range(2, n):
> > >>        if n % x == 0:
> > >>            x
> > >>
> > >> This doesn't work as intended (filtering out the non-factors).  How  
> > >> to
> > >> make it work?  The only way I can think of is to make (if 0: 1)  
> > >> return
> > >> a special "non-value" which loops will then filter out.  But then we
> > >> all know what happens to non-values.
> > >>
> > >> So how would you solve this problem?
> > >
> > > By writing it properly ;-)
> > >
> > > factors = for x in range ( 2, n ):
> > >    if n % x == 0:
> > >        yield x
> > >
> > > As I mentioned previously, in order to merge the concept of generator
> > > with a for-expression would require bringing in the yield keyword,  
> > > just
> > > as it does now for generator functions.
> > >
> > > The example you gave would evaluate to None (or perhaps an empty  
> > > list or
> > > generator - that's a detail that would take more consideration before
> > > defining it).
> > >
> > 
> > OK, but this seems to me incompatible with current Python:
> > 
> > def chain(I, J):
> >      for i in I: yield i
> >      for j in J: yield j
> > 
> > Currently
> > 
> >  >>> '-'.join(chain('spam', 'eggs'))
> > 's-p-a-m-e-g-g-s'
> > 
> > With your proposal, the first *expression* (for i in I: yield i) will  
> > evaluate to something like iter(I) and then be discarded.  Then the  
> > second *expression* (for j in J: yield j) will evaluate to something  
> > like iter(J) which will be discarded.  So chain('spam', 'eggs') will  
> > return None.
> 
> It seems you have me on this one.  There's clearly other ways to do the
> same thing, but since backwards-compatibility is a prerequisite I'll
> have to concede the point. 
> 
> A potential solution would to be to use a different keyword than "yield"
> to separate current syntax from my proposed syntax (that is, distinguish
> expression-scoped yield from function-scoped yield), and just side-step
> the issue, but that seems unappealing to me.

Actually, a few more minutes of pondering got me a solution I don't find
abhorrent.  Let yield mean what it currently does.  Instead, let
"continue" accept an optional parameter (like "return").  Then your
above example continues to work and my proposed change would look like:

for i in j:
    continue i

I haven't considered this too deeply, but it is at least consistent with
"return" syntax and doesn't add a new keyword.

Regards,
Cliff




More information about the Python-ideas mailing list