Ken Jin <[email protected]> added the comment:
@larry
> Is this "surprising, but required" behavior due specifically to this being a
> backwards-incompatible change?
Yes. That's the main factor. I've since learnt that there's sadly more to it
though :( (see below).
> Does that mean I don't have the problem you're solving by reversing the order
> of namespace lookup, and I can just pass globals and locals in like normal?
I think it depends on the ergonomics of the function you're trying to achieve.
I admit I haven't been fully keeping up with the inspect.get_annotations issue
(sorry!), but here's what I learnt from get_type_hints:
(Partly copied over from PR 25632)
Example:
from typing import TypeVar, Generic
T = TypeVar('T')
class A(Generic[T]):
__annotations__ = dict(
some_b='B'
)
class B(Generic[T]):
class A(Generic[T]):
pass
__annotations__ = dict(
my_inner_a1='B.A',
my_inner_a2=A,
my_outer_a='A' # unless somebody calls get_type_hints with
localns=B.__dict__
)
>>> get_type_hints(B)
Currently (globalns then localns):
{'my_inner_a1': <class '__main__.B.A'>, 'my_inner_a2': <class '__main__.B.A'>,
'my_outer_a': <class '__main__.A'>}
Swapped (localns then globalns):
{'my_inner_a1': <class '__main__.B.A'>, 'my_inner_a2': <class '__main__.B.A'>,
'my_outer_a': <class '__main__.B.A'>}
I realized that looking into globalns then localns is a necessary evil: doing
the converse (looking into localns first then globalns) would mean there is no
way to point to the shadowed global `A`: it would always point to the local
`B.A`. Unless of course you pass in localns=module.__dict__ or
localns=globals().
Ultimately I think it's a sacrifice of ergonomics either way; looking into
localns then globalns will require passing in the module's __dict__ to refer to
a global being shadowed, while the converse (globalns then localns) introduces
surprising eval behavior. Both are kind of tacky, but globalns then localns is
slightly less so IMO. If the user wants to specify the inner class, they can
just annotate 'B.A', if they want the outer, it's 'A'. But the localns then
globalns approach will always point to `B.A`, the only way to access the
shadowed global `A` is to pass in the strange looking argument
localns=module.__dict__.
Phew, my head's spinning with localns and globalns now. Thanks for reading! I
think it's your call. I'm inexperienced with elegant function design :P.
----------
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue42904>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com