Emulating Pascal input

Quinn Dunkan quinn at regurgitate.ugcs.caltech.edu
Thu May 23 14:45:01 EDT 2002


On Wed, 22 May 2002 12:03:20 +0100, Michael Williams
<michael.williams at st-annes.oxford.ac.uk> wrote:
>######### Python code ###########
># Either: stdin
>linestring = raw_input()
>
># Or: file
>linestring = f.readline()

I would suggest:

f = sys.stdin
f.readline()
f = open('input')
f.readline()

to emphasize that they are the same operation.

>linelist = string.split(linestring)
>x = int(linelist[0])
>y = int(linelist[1])
>
># Or perhaps
>linestring = raw_input()
>x,y = string.split(linestring)  # x and y are now strings eg. '1' 
>                                # and '2'
>x = int(x)
>y = int(y)

This is easier to write as:

x, y = map(int, f.readline().split())

If the input is in the wrong format, python will automatically throw a nice
error message for you.  I'm not sure what the pascal will do in case of error.

>I have been attempting to write such a function in Python but have been 
>struggling with (a) the lack of pointers, and (b) my total ignoarnce of
>classes, which I suspect would be helpful. Here's what I have so far

classes are not likely to be helpful, I think you just want a utility function
:)

>(although note there is no error handling--give it a string response and
>it falls over and dies, give it the wrong number of responses and it
>falls over and dies, etc., etc.):

Falling over is what error handling is all about, isn't it?  I thought you
didn't have error handling when errors were silently ignored, and your program
blew up later (as C and perl tend to do), and you did have error reporting when
errors were detected and reported in an orderly fashion, and had to be handled.

>############ ninput.py ############
>
>import string
>
>def ninput(n, fin = None, prompt = '', sep = None):
>    
>    # If not file input then get string from stdin, else get from file
>    if fin == None: linestring = raw_input(prompt)
>    else: linestring = fin.readline()
>    
>    # Split up into list with optional seperator argument
>    responses = string.split(linestring, sep)
>    
>    for i in range(len(responses)):
>        if '.' in responses[i] or 'e' in responses[i] or \ 
>        'E' in responses[i]:
>            # i.e. if it looks like a float
>            responses[i] = float(responses[i])
>        else:
>            # i.e if it doesn't look like a float    
>            responses[i] = int(responses[i])
>            
>    # If there was only one response then don't return a list.
>    if len(responses) == 1: responses = responses[0] 
>    
>    return responses[:n]

Wow, that's complicated.  I'd write this as something like:

def read_floats(fp):
    return map(float, fp.readline().split())

I'd suggest that it's better style to only return one type rather than
make the caller figure it out for itself.

>####################################
>
>And here is a usage example:
>>>> x, y  = ninput(2)
>5 6.0
>>>> print x, type(x)
>5 <type 'int'>
>>>> print y, type(y)
>6.0 <type 'float'>
>
>This has the limitation that the user must pass the number of results
>they expect back. This is done implicitly in the Pascal version too (the
>number of variables passed to the function). However, error checking is 
>difficult as this version stands.

In this version, the user specifies how many results he expects on the left
side of the '='.  If there is an error (too many, too few), that will be
flagged and reported.  If you want to handle it, catch ValueError:

while 1:
    try:
        x, y = read_floats(sys.stdin)
    except ValueError, x:
        print 'bad input:', x
    else:
        break

>This is possibly what should be expected. However, passing the numerical
>argument representing the number of results expected does not strike me
>as a particularly graceful solution. We would prefer something like the
>Pascal way, where the global variables in which the results are to be
>stored are passed as parameters. Can anyone suggest a way of doing this?

Yeah, just leave out the numerical argument :)

Python is one of those languages that espouses returning values by returning
them, rather than returning them with "out" parameters (personally I've never
quite understood the logic of that one, except in a prolog-ish situation), so
if you're thinking in terms of "out" parameters, it's going to fight you.
Give in.  Use return values.  C'mon, everyone's doing it.

>And if such an equivalent to the Pascal construct was implemented, what
>would be the chances of getting it included in, say, the string module
>of core Python. We would like such a function but would be reluctant to
>use it as we would then be teaching our students a ``dialect'' of
>Python.

Writing a few utility functions doesn't relegate you to dialect backwoods.
Everyone has a library of generic utilities they collect over time.  Small
reusable utilities are one of the things dynamic languages like lisp and python
are about.  Just make a mike_util.py and have your students import it, or
import it in site.py.




More information about the Python-list mailing list