On Fri, Sep 23, 2016 at 6:24 AM Nick Coghlan
On 23 September 2016 at 13:06, Steven D'Aprano
wrote: On Thu, Sep 22, 2016 at 07:21:18PM +0000, אלעזר wrote:
"Expression" is something that you need its value right now, and "annotation" is something that, well, annotates the code you see right now.
Right. In the case of Python, function annotations **do** have a runtime effect: the expressions are evaluated, and the evaluated results are assigned in function.__annotations__ and made available for runtime introspection.
Don't think that function annotations are **only** for the static type checker. Python is a much richer language than that!
If folks are after a simple non-type-checking related example of annotation usage, the "begins" CLI library is a decent one: https://pypi.python.org/pypi/begins
That lets you supply command line help for parameters as annotations:
============ In Python3, any function annotations for a parameter become the command line option help. For example:
import begin @begin.start # doctest: +SKIP ... def run(name: 'What, is your name?', ... quest: 'What, is your quest?', ... colour: 'What, is your favourite colour?'): ... pass
Will generate command help like:
usage: holygrail_py3.py [-h] -n NAME -q QUEST -c COLOUR
optional arguments: -h, --help show this help message and exit -n NAME, --name NAME What, is your name? -q QUEST, --quest QUEST What, is your quest? -c COLOUR, --colour COLOUR What, is your favourite colour? ============
It's not a substitute for something like click or argparse when it comes to more complex argument parsing, but it's a good example of the kind of simple pseudo-DSL folks have long been able to create with annotations independently of the type hinting use case.
That's a very nice use, and I was wrong - I did know it; I've found it not long ago when I wanted to implement it myself... And guess what? It does not require eager evaluation _at all_. No decorator-helped-annotation mechanism require eager evaluation built into the language. Lazy evaluation is more general than eager, in that it can always be forced (and not the other way around). def eager_annotation(f): f.__annotations__ = {k:v() for k, v in f.__annotations__} return f Use @eager_annotation wherever you like, or collapse it into other decorators. You don't need @eager_annotation for type annotations, or any other form of annotation without runtime semantics. On the other hand - if you do want side effect in this function's annotations, well there's better be some nice big @EAGER! decorator above it. Elazar