Oh, happy day!  eval() has been expunged from my program!!  I will now
continue from where I left off earlier.

On Sun, Mar 24, 2019 at 12:22 AM Cameron Simpson <c...@cskk.id.au> wrote:
>
> On 23Mar2019 22:15, boB Stepp <robertvst...@gmail.com> wrote:
>
> The lambda is just a single line function definition, and doesn't get a
> function name.

> So your get_input name now accepts a "date_constructor" parameter and
> you would change the input step from this:
>
>     try:
>         identifier = int(input(input_prompt))
>         if date_value_err_ck:
>             date(*date_value_err_ck)
>     except ValueError:
>
> to this:
>
>     try:
>         value = int(input(input_prompt))
>         date = date_constructor(value)
>     except ValueError:

You could not know this from the code I showed (As I pared it down to
illustrate my problem.), but I am also using get_input() to pull in
from the user non-date values, too, but they are also all integers:
pages_read and total_pages_to_read.  Because of this, for these latter
two items, "date_value_err_ck" will be assigned "None", which is why I
have the "if date_value_err_ck:".

> So you're passing in a function to make the date, and only calling it
> once you've read in the value.
>
> This solves your use of goal_year before it is defined in 2 ways: it
> doesn't use the value before the call to get_input and also the name
> "goal_year" in the constructor function is local to that function - it
> may as well be called "year".
>
> Now to your conditions. You have:
>
>     'conditions': [
>         ('goal_year < date.today().year',
>             "Have you invented a time machine?  If not, please enter a"
>             " year that makes more sense!"),
>         ('goal_year >= date.today().year + 100',
>             "Have you discovered the secret to eternal life?  And how"
>             " long is this book anyway?  Please enter a year that"
>             " makes more sense.")]}
>
> These seem to be tests for bad values (personally I tend to write tests
> for good values, but this is an arbitrary choice). These should also be
> written as lambdas:

I just like writing corny error messages in response to bad values. ~(:>))

> But wait, there's more!
>
> After you have phase 1 complete (inputting goal_year) you then want
> goal_month.
>
> Let me introduce you to the closure:
>
> For the goal_year you have the year-based constructor using only the
> input value:
>
>     'date_constructor': lambda goal_year: datetime.date(goal_year, 1, 1),
>
> in your setup dict. For the goal_month you want both the goal_year and
> the input value. So...
>
>     'date_constructor': lambda goal_month: datetime.date(goal_year, 
> goal_month, 1),
>
> But, I hear you ask, I'm not passing in the goal_year to the get_input()
> for the month value! Indeed, your code will look like this:
>
>     goal_year_params = {
>         ....
>         'date_constructor': lambda goal_year: datetime.date(goal_year, 1, 1),
>         ....
>     }
>     goal_year = get_input(**goal_year_params)
>     goal_month_params = {
>         ....
>         'date_constructor': lambda goal_month: datetime.date(goal_year, 
> goal_month, 1),
>         ....
>     }
>     goal_month = get_input(**goal_month_params)
>
> That's your plan, yes?

You understand me perfectly!

> Well, when you define the goal_month constructor lambda function,
> goal_year _is_ a local variable. And _because_ it is not a parameter of
> the lambda, the lambda finds it in the scope where it was defined: the
> scope at the bottom of your programme.
>
> This is called a "closure": functions has access to the scope they are
> define in for identifiers not locally defined (eg in the parameters or
> the function local variables - which are those assigned to in the code).

This is so cool and useful!  I recall seeing this mentioned for nested
functions, but did not know it worked for lambdas as well.

This has been incredibly helpful and educational!  Many thanks!!

-- 
boB
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to