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 - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor