[Tutor] Fwd: Re: How to refactor a simple, straightforward script into a "proper" program?

Alan Gauld alan.gauld at yahoo.co.uk
Sun Jan 5 19:30:12 EST 2020


On 05/01/2020 05:40, boB Stepp wrote:

>>>     while True:
>>>         try:
>>>             return str_converter(input(msg))
>>>         except ValueError:
>>>             if str_converter == int:
>>>                 print("\nPlease enter a whole number!")
>>>             elif str_converter == date.fromisoformat:
>>>                 print("\nPlease enter a valid date in the following
>>> format yyyy-mm-dd!")
>>
>> And if its not one of those types? I get a ValueError raised then it
>> does nothing. It just returns None. That's not very friendly.
> 
> Huh?  Joel said something similar.  Maybe I am being dense, but it
> *does* do something.  If the user types in something that is not one
> of the allowed types, he gets a helpful message telling him/her what
> the program is expecting, and the program loops back to the original
> message requesting input.

My bad it does not "return None" in the technical sense.
It displays nothing just returns to the prompt.
Try writing your own string convertor:

def myInt(s):
   return int(s)

Now use myInt as the string convertor and see what happens...
It does 'work' but is less user friendly.

> But it also does date input.  And if in the future I wanted other
> sorts of input I need only add new string converters for the new data
> types.

Yes, but the udr of your module will expect to be able to write their
own string convertors and they wont work without modifying the module -
thats bad.

You would need to have a dict of string convertors and error messages so
that the error handler could look up the error message using the string
convertor as a key:


except ValueError:
       print conv_msg[string_convertor]

And the user can then add their own error message:

module.conv_msg[myInt] = "Enter an integer"


>> This sounds like a reusable function, but in fact its pretty tied into
>> the problem at hand.
> 
> Again, I wonder if I am being dense, but my intent with this function
> is to handle a variety of input types.  I would have to add new
> ValueError possibilities for new data types.  Is this what bothers
> you?

Yes because when I download your "industrial strength" module I
discover I either have to contact you every time I need a new
string converter or I have to fix up the module myself!
Neither is good from a users perspective.

> Hmm.  I see that in case of ValueError it could look elsewhere for
> what sort of user friendly error message to display for a particular
> value of str_converter.  Is this what you are getting at?

Yes, see the dict example above.

> presented in the "simple" script.  I have quickly looked over D. L.
> Neil's comments, and, combined with yours, wonder if I should redesign
> the whole shebang from the ground up?  Maybe this problem does need an
> OO approach.

You shouldn't need an OO approach for something this small.
But you do need a bit of a rethink in tems of splitting out the
functions cleanly. And exactly what is published API and what
is just internal utility code.

> I grudgingly concede your point.  Grudgingly because now I have to
> figure out how to accomplish this.  ~(:>))

I think exceptions are the way to go.

>> ppd = calc_pages_per_day(bp,rp,due)
>>
>> Maybe its just me but the calc seems implied by the function call.
> 
> But I thought the great preference was for function and method names
> to be verbs not nouns?

Hmmm, yes. OK I'll give you that one :-)

>> Would you really say page if it was 0.5 pages per day?
> 
> Actually, yes.  Just as I would say a half page per day.  OTOH, I
> would say zero pages per day.  Maybe I need to dust off a grammar
> book...

a half page is not the same as 0,5 pages.
The a forces it to single. So in your code you need to add
an 'a' before the value to make it grammatical.
Thats more work, but doable, but what would you say
for a value like 0.82? What kind of fraction is that?
Are you going to convert it to say

a 82 hundredth of a page?

Good luck with that...

>> I'd only use 'page' if it was exactly 1.
>>
>> But since its a float you need to use an epsilon value.
>> So
>>
>> e = 0.0001
>> if 1-e < pages_per_day < 1+e:
>>     word_to_display = 'page'
>> else: word_to_display = 'pages'
> 
> Do I really need an epsilon value for this particular case?  I am not
> seeing where my intentions would fail here.  Can you provide an
> example?  

This is because the computer cannot accurately represent floats so you
may get a value like 0.999999999 or 1.00000001 when you want to treat it
as 1. So you either use an epsilon or you do a float to some minimal
number of decimals.

> thought if the user wishes to be silly here, why not?

Its not about the user, its the floating point division
in a digital computer.

> I originally in my code did not use mixed quotes.  But when I saved
> the file my new code formatting tyrant, Black, changed my consistent
> quoting style to mixed quotes.  Apparently it insists on all double
> quotes unless there are embedded quotes within when it converts those
> to single quotes.

Yukkkk!

>> 2) if a function isn't generally reusable make it obvious
>>    by putting an underscore in front of the name. (or
>>    make it generally reusable...usually much harder :-)
> 
> This is where I was hoping for some concrete, helpful examples.  I do
> indeed find this "much harder".

Everyone does. Management routinely ask devs to create reusable code,
but studies show that writing reusable code is from 3-5 times more
expensive than writing single-use code. Some studies say more like 10
times if you factor in maintenance costs too.

And there is no easy answer, it takes painful lessons and
experience, and you'll still mess it up!

>> 3) separate presentation and logic.
> 
> Again, I find this not so easy.

This is easier and just takes a little practice to get used to it.
Basically every function should either do display or logic. If its
doing logic then return values that the caller can use/display.


> FEATURE CREEP!  Actually sounds like an interesting addition.  But I
> don't much like eReaders myself.  

I didn't used to but, on holiday, I save a ton of weight by taking a
Kindle. And having got used to them I now occasionally even read
tech books on it. Although code formatting often gets messed up.
But I'm currently reading a book on curses programming in C and
converting it to python - maybe to become a page in my tutor
someday - and that's a Kindle book.


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos



More information about the Tutor mailing list