iteration (was RE: "sins" (aka, acknowledged language problems))

Alex Martelli Alex.Martelli at think3.com
Fri Dec 17 08:23:45 EST 1999


Fredrik Lundh writes:

> > def copy(regex, dict, inp=sys.stdin, oup=sys.stdout):
> >     def repl(match,dict=dict):
> >         return eval(match.group(1),dict)
> >     while 1:
> >         line = inp.readline()
> >         if not line:
> >             break
	[snip]
> hmm.  by some reason, my brain treats that
> while/if/break stuff as one large "glyph".  am
> I the only one here who has a brain equipped
> with a 2D pattern matcher? ;-)
> 
No, I think that's pretty common -- why, some
people are even rumored to live in a 3D world:-).

Similarly, in languages having nothing except
IF and GOTO as flow-control constructs, one
eventually learns to recognize such idioms as
LOOP:	IF not condition GOTO OUT
		statements
		GOTO LOOP
OUT:	
as equivalent to what would be
		WHILE condition
			statements
in a better-equipped language.

Do you consider that this amazing pattern
recognition ability of the human brain is
some argument against introducing more
explicit and concise constructs for extremely
usual patterns, such as IF/GOTO/GOTO?-)


> > But why can't I change those 4 lines to, say:
> >     while line := inp.readline():
> 
> how about:
> 
> import fileinput
> for line in fileinput.input():
> 
Wouldn't that tie me to using sys.stdin,
rather than giving the caller the option
of supplying some other file object (or
other object implementing readline) in its
stead (so that the caller would need to
muck with sys.argv to make me read
other files, and be out of luck for other
customizations)?  Wouldn't it further
break on "MS-DOS 8+3 filesystems",
at least according to the 1.5.2 docs?

Seems a high-ish price to pay to get
better syntax.

Maybe it would be better in this case
to change the argument default
	inp=sys.stdin
to
	inp=fileinput
and the loop to
	for line in inp.input()
which gets me the good syntax and
is just about as easy for the caller
to customize.

I was about to add that "of course,
this doesn't help in other similar
cases of iteration" when I realized
that in a sense it does -- the Python
answer to "how do I make a decent
looking loop rather than using a
4-line glyph" could be "beg, borrow
or steal an iterator object that doles
out items one at a time so you can
use it in a for loop" -- which takes
me very close to a recent post of
mine to this list/newsgroup, the 2nd
part of the "random reflections"
post, where my thirst for elegant
generalizations brought me a (very
mild & courteous) reproach by Tim.


Partially-undaunted, I now ask...:


Given the "4-line glyph":
>      while 1:
>          item = mynextitem('foo')
>          if not is_still_ok(item,'bar'):
>              break
> 
I would like to translate this to something like:

	for item in iter(mynextitem,('foo',),is_still_ok,('bar',)):

(actually, I would dearly LOVE to translate it to
	while is_still_ok(item:=mynextitem('foo'),'bar'):
but let's assume there IS no ':=' operator:-).

Of course, I'd have reasonable defaults, e.g. 
is_still_ok would default to normal truth-testing 
unless explicitly specified, etc.

Is it reasonable for me to try to design a "class iter"
for such uses, or am I again shooting for misplaced
and excessive generality, and/or likely to meet
serious performance trouble, etc...?

Offhand, I'd write something like (capitalizing on
Tim's earlier suggestion to ignore the "key"
passed to __getitem__):

class iter:
	def __init__(self,next,na=(),test=None,ta=()):
		self.next=next
		self.na=na
		self.test=test
		self.ta=[None]+map(None,ta)
	del __getitem__(self,key):
		item = apply(self.next,self.na)
		if self.test:
		    self.ta[0] = item
		    if not apply(self.test,self.ta):
			pass # do what, here...?
	      else
		    if not item:
                        pass # do what, here...?
		return item

but what should I place instead of the 'pass'
statements, to make the 'for' construct
terminate correctly...?  In other words, what
does __getitem__ return, or what exception
does it raise, to make a "for x in y" statement
terminate correctly?  I see from the sources
for fileinput.py that an IndexError gets
raised -- is that the "right" way to do it (is
it documented somewhere as such), or does
it just "happen to work" on the current
implementation of the interpreter...?


TIA once more to all you helping this newbie
in his discovery of this great language...


Alex







More information about the Python-list mailing list