Version 3 is now at http://www.rcblue.com/Python/yen-USD-v3.txt . Am
I done? Or will a v4 be necessary/advisable?
At 05:37 AM 9/7/2006, Andrei wrote:
>Dick Moores <rdm <at> rcblue.com> writes:
> > (1) Have I handled possible user-errors OK?
>
>I've tested it a bit and it seems to be quite robust.
Thanks.
> > (2) Is my roundingN() function OK? Is there a better way to write it?
> > Will the line
> >
> > n = round(float(n)*(10**rounding))/(10**rounding)
>
>Using format strings is easier I think. "%.2f" % 2.34234 will give '2.34'.
Yes, I finally got that implemented, thanks to your further assistance.
> > get me into trouble with the flakiness of float(n)? In testing I
> > didn't find any problems, but ..
>
>Nah. Float accuracy is only a problem if you need around lots of significant
>digits (16 or so).
>
> > (4) I wanted to call closingMessage() in main(), but in some cases,
> > if it's in main() it gets 2 successive calls. I can't figure out why.
> > Would IDLE's debugger be of use here? (I've never used it before.) I
> > haven't been able to find up-to-date IDLE help.
>
>I think the main loop could be improved.
>
>1) Python idiom is to *not* always call main(), because that makes
>it impossible
>to use functions from your module in a different program: importing the module
>would start running the converter, while you might only be
>interested in reusing
>getRate(). It's better to put the following code at the bottom instead:
>
>if __name__ == "__main__": # if module is running standalone (not imported)
> main()
Done.
>2) If the application is used extensively, you'll exceed the maximum recursion
>depth, because what the application does is essentially this (if the user
>chooses to continue):
>
> main calls again calls main calls again calls... ad infinitum
>
>This is called recursion - main essentially calls itself. You can test what
>happens by disabling the entire main loop up to "again()" as well as the
>raw_input line in again(). Python will quickly give up with:
>
> File "yen.py", line 164, in again
> main()
> File "yen.py", line 184, in main
> again()
> RuntimeError: maximum recursion depth exceeded
>
>It's better to have a main() which does something like this:
> - get the conversion rate and store it in some (global?) variable
> (instead of asking for it every time)
> - start a while True loop:
> -- get the rate , currency and amount
> -- calculate and print result
> -- ask the user whether to do it again and stop loop if answer is No
Your point about recursion is well-taken, but I doubt that the user I
have in mind will run into it. And he would be as likely to want to
vary the exchange rate as the amount.
>3) The function again() uses an internal variable called 'again'. This is not
>good coding practice (confusing).
>3b) Note that this is a variable local to the again() function, so you cannot
>use it in the main() anyway:
>
> again()
> if again:
> break
>
>"if again" actually checks if there is something called 'again' with a
>non-zero/non-empty/non-None/True value. Your function is such a
>thing, so the if
>condition always evaluates as True. (Tip: try "print again" before the "if
>again", you'll see something like "<function again at 0x00B04670>").
>This is of
>course related to recursion problem above.
>
>Improved version would be:
>
>def again():
> answer = raw_input('Another?')
> return answer in 'yY' # evaluates to True if the user pressed 'y' or 'Y'
>
>def main():
> # stuff
> while True:
> # stuff
> if not again():
> closingMessage()
> return None
>
>Notice that this code is also easier to read than the original, because it's a
>literal translation of you intention: if the user doesn't want to
>run it again,
>say goodbye and stop.
Thanks. Between yours and Danny's help, I finally understand the
problem. I haven't heard back from Danny yet, but I think I've
corrected the problem.
>4) Function names are important and should be chosen in such a way
>that they are
>not confusing. Most of them are OK, but commas() is non-descripting
I've renamed commas() to numberCommas(). Is that descriptive enough?
I'm reluctant to go with even a longer name. I'll be using it a lot elsewhere.
> and
>printResult() is confusing - it doesn't just print, it actually calculates. A
>third party interested in reusing your calculation routine wouldn't expect the
>printResult to be the culprit.
I've separated printResult() into calculateAnswer() and printAnswer().
>5) Checks like "if currency in 'USD'" work, but are a bit unstable.
>It works in
>this case because Yen and USD have no letters in common, so input of
>'y', 'e' or
>'n' all lead to 'Yen', while 'u', 's' and 'd' go to 'USD'. Imagine
>you'd extend
>your program to also handle 'AUD', 'EUR', 'CAD' and 'SEK'. The 'e' would now
>lead to Yen instead of EUR.
Thanks for that general point, but I'll revise the function when necessary.
>6) I would trim down the the checks in checkAmount:
>- there is no need to use "continue" in that loop, because the loop will
>continue anyway. 'continue' is only useful if there is some code later in the
>loop that you want to skip.
>- separate checks for negative and zero values seem pointless. Either handle 0
>as any other number (gives result 0), or put a single check on
>"amount <= 0" and
>inform the user that a number larger than 0 is required.
>Here's a modified version:
>
> def getAmount(currency):
> while True:
> useramount = raw_input('Amount: ').lower().strip()
> if useramount in 'qx':
> return useramount
> try:
> amount = float(useramount)
> except ValueError:
> continue # we want to skip the code below
> if amount <= 0:
> print "Amount must be more than 0."
> else:
> return amount
>
>Using multiple returns in a single function is sometimes frowned
>upon; but then
>again, so are break and continue :).
I didn't know till now that a return statement could be used inside a
while loop, to close the function. I had thought that with a "while
True:" I always had to break out of it with a "break".
Using your example, I revised getRate(), getAmount(), and
getYenOrUSD(). Cut down the number of continue's and cut out all break's.
Thanks very much, Andrei.
Dick
_______________________________________________
Tutor maillist - [email protected]
http://mail.python.org/mailman/listinfo/tutor