[Tutor] How to type annotate complex dictionary containing lambdas?
Mats Wichmann
mats at wichmann.us
Sun Nov 17 10:25:52 EST 2019
On 11/17/19 1:52 AM, Alan Gauld via Tutor wrote:
> On 17/11/2019 05:32, boB Stepp wrote:
>> My best effort so far to type annotate the dictionary below is to use
>> "Any" for the dictionary values. Is there a better substitute for
>> "Any" that would more precisely type annotate these dictionary values?
>
> To be honest I wouldn't even be trying I'd be more concerned with
> getting rid of such a messy dict and replacing it with a class.
>
> Type hints are no substitute for clean code.
Indeed. It turns out that classes are (normally) expressed as a dict,
so there's not even that much to do to convert.
Here's a simple class definition that contains some of your dict, based
on snipping a few lines and just changing the syntax, no attempt to make
any logic changes:
class Foo():
greeting_msg = "Please enter the date by which you wish to attain
your goal.\n"
input_prompt = "Enter year of your goal as an integer: "
date_value_err_ck = lambda goal_year: date(goal_year, 1, 1)
err_msg = "That is not a valid year. Please try again."
print(Foo.__dict__)
And when run the print gives you (I took the liberty of putting in line
breaks for readability):
{'__module__': '__main__',
'greeting_msg': 'Please enter the date by which you wish to attain
your goal.\n',
'input_prompt': 'Enter year of your goal as an integer: ',
'date_value_err_ck': <function Foo.<lambda> at 0x7f6f3d224c20>,
'err_msg': 'That is not a valid year. Please try again.',
'__dict__': <attribute '__dict__' of 'Foo' objects>,
'__weakref__': <attribute '__weakref__' of 'Foo' objects>,
'__doc__': None}
look familiar? :) Python has added some special symbols as well but
otherwise it's the same thing. So the choice of "use a dict instead of
a class definition because it's simpler" isn't actually always simpler,
and here it isn't as you've ended up defining a list of tuples or
lambdas. Like Alan, I shudder :). The keys in your dict are all strings,
those would map directly to the attribute and method names in the class.
In addition, the general guideline is if you're going to give it a name,
don't use a lamba, because it's no longer anonymous at that point,
defeating the only purpose lambda actually has. You've given the first
lambda the name date_value_err_check, which means it's actually:
def date_value_err_ck(self, goal_year):
return date(goal_year, 1, 1)
you'd probably expand that to do all the work of "conditons" (though we
don't see the code to use it)
As you your actual question...
>> goal_year_params: Dict[str, Any] = {
the two types that the dict's values can be per your snip is str or
list, so start there:
goal_year_params: Dict[str, Union(str, List)]
if you want to go further you can then specify what the list consists
of, etc.
>> "greeting_msg": "Please enter the date by which you wish to attain"
>> " your goal.\n",
>> "input_prompt": "Enter year of your goal as an integer: ",
>> "date_value_err_ck": lambda goal_year: date(goal_year, 1, 1),
>> "err_msg": "That is not a valid year. Please try again.",
>> "conditions": [
>> (
>> lambda goal_year: goal_year < date.today().year,
>> lambda goal_year: print(
>> "Have you invented a time machine? If not,
>> please enter a"
>> " year that makes more sense!"
>> ),
>> ),
>> (
>> lambda goal_year: goal_year >= date.today().year + 100,
>> lambda goal_year: print(
>> "Have you discovered the secret to eternal life?
>> And how"
>> " long is this book anyway? Please enter a year that"
>> " makes more sense."
>> ),
>> ),
>> ],
>> }
>
>
More information about the Tutor
mailing list