There is some test code:
some_type = int
def func0():
def func1(arg: some_type, /):
pass
func0()
And I get the following error:
Traceback (most recent call last):
...
SystemError: no locals when loading 'some_type'
However the code below works as expected:
some_type = int
def func0():
def func1(arg: some_type):
pass
func0()
And this one is also valid:
some_type = int
exec('''
def func1(arg: some_type, /):
pass
''')
I know that annotations will no longer be evaluated at definition time in future versions; also it is possible to activate such behaviour in 3.7+ versions. Something like
from __future__ import annotations
some_type = int
def func0():
def func1(arg: some_type, /):
pass
func0()
has no problems as well. However, the question is about the current strange behaviour at function definition time. some_type
is in no way a local variable of func0
, though python thinks so. One more fine version:
def func0():
some_type = int
def func1(arg: some_type, /):
pass
func0()
I've read PEP 570 but not found anything about annotations declarations there.
My python version:
sys.version_info(major=3, minor=8, micro=0, releaselevel='final', serial=0)
This is a bug in cpython -- I've opened an issue for it here: https://bugs.python.org/issue39215
looking at the disassembly of the two functions, it appears as though it incorrectly uses LOAD_NAME
instead of LOAD_GLOBAL
when building the annotation type -- here's the diff between one with and without positional only arguments:
$ diff -u <(python3.9 -m dis t2.py | sed 's/0x[a-f0-9]*/0xdeadbeef/g;s/t2\.py/FILENAME/g') <(python3.9 -m dis t3.py | sed 's/0x[a-f0-9]*/0xdeadbeef/g;s/t3\.py/FILENAME/g')
--- /dev/fd/63 2020-01-04 16:34:27.372004436 -0800
+++ /dev/fd/62 2020-01-04 16:34:27.372004436 -0800
@@ -10,7 +10,7 @@
16 RETURN_VALUE
Disassembly of <code object f at 0xdeadbeef, file "FILENAME", line 1>:
- 2 0 LOAD_NAME 0 (int)
+ 2 0 LOAD_GLOBAL 0 (int)
2 LOAD_CONST 1 (('arg',))
4 BUILD_CONST_KEY_MAP 1
6 LOAD_CONST 2 (<code object g at 0xdeadbeef, file "FILENAME", line 2>)
EDIT: and here's a pull request to fix this (should land in 3.8.2 and 3.9.0a3 if my guess about timing is correct): https://github.com/python/cpython/pull/17826