Incorrect status of name in class def or module level, before being assigned or after being deleted.
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Python
- Estrellas
- 20.6k
- Forks
- 3.3k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
There are some circumstances when mypy interprets a name (x) in a module or class scope as inner when it is outer, or vice versa. (There appears to be no such problem with function scopes.)
I use the term inner to mean that the python interpreter will resolve the name x in the scope. It it is not currently bound in the scope, it is a NameError. outer means that the interpreter will try to resolve the name x in some enclosing scope.
I have determined by trial and error the rules for when a name is inner or outer, and what value a name is resolved to. I wrote a script that applies these rules in a great variety of combinations of nested class and function scopes and uses of the name x, and verifies that the expected value of x, or NameError, is the actual result. You'll need to rename it to gentest.py in order to run it yourself (python 3.7).
x is inner when:
- it is not declared global or nonlocal
- and
xis bound or deleted anywhere in a function scope.- or
xis currently bound in a class or module scope.
An inner x is resolved:
- In a function
f"- in a binding operation in the body of
fthis binds a new value tox. - elsewhere in the body of
fby the current bound value if any, else a NameError. - in the body of a nested function or class
s(at whatever level) wherexis an outer name ins, which is resolved inf: likewise by the current bound value if any, else a NameError. If this occurs after executing the body off(becausesis a function which was saved and later called), it is the same as though the call tosoccurred at the end of the body off.
- in a binding operation in the body of
- In a class
C- in a binding operation in the body of
Cthis binds a new value tox. - elsewhere in the body of
Cby the current bound value. Note, if there is no current bound value ofx, thenxis an outer name. - Note,
xwill never be resolved in any enclosing class or function scope, because the resolution rules skip over class scopes.
- in a binding operation in the body of
- in a module:
Same as for a class, except that the namexcan also appear in a nested class or function.
An outer x is resolved in any scope, possibly restricted to functions only, resulting in a value, or not bound, or in the restricted case, no scope.
When restricted, x is resolved:
- In a module scope, no scope.
- Else in a class scope, by
xin the next enclosing scope. - Else if
xis declared nonlocal, byxin the next enclosing scope. - Else if
xis declared global, no scope. - Else, by
xin the next enclosing scope. Note, sincexis outer, it is neither assigned nor deleted here.
When unrestricted, x is resolved:
- In a module scope, by the value of
builtins.xif it exists, else not bound. Note, global declarations are ignored and nonlocal declarations are syntax errors. - Else if
xis declared nonlocal, byxin the next enclosing scope, restricted. - Else if
xis declared global, byxin the module namespace - Else, as follows: Note, since
xis outer, it is neither assigned nor deleted here.- If resolved by
xin the next enclosing scope (restricted) succeeds, then by that result. - Otherwise, by
xin the module scope.
- If resolved by
A special situation occurs for augmented assignments like x += y in class and module scopes. The current value of x is found, then x.__iadd__(y) is called, then the result is assigned to x. The two x's can be in different scopes
One surprising thing, which I don't think is clear in the Python docs, is the value of a name in a class def which is bound or deleted in the class body, whenever there is no binding of that name during the execution of the class body. If the name is captured by some enclosed function scope, then the value may be found in searching enclosed functions then globals then builtins, whereas if the name is not captured, it skips the enclosed functions.
You may wish to include the above name resolution rules in your own documentation. I will forward it to the Python people as an issue about their documentation.
Your Environment
- Mypy version used: 0.950
- Python version used: 3.7
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Cambia el nombre del script adjunto gentest.py.txt a gentest.py y ejecútalo con Python 3.7 para reproducir los casos documentados de resolución de nombres. Compara los resultados esperados con el comportamiento de mypy, localiza después la implementación de la resolución de nombres y añade cobertura de regresión para los casos fallidos en el ámbito de clase y de módulo. Se considera terminado cuando mypy informe de estos casos de forma coherente con las reglas indicadas.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- python
- Área
- devtools
- Tipo de issue
- Error
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Estado de actividad
- Estancado
- Claridad
- Bastante claro
- Aptitud para principiantes
- 25/100