python - tutorial - httpresponse django example
¿Cómo puedo saber de qué módulo se importa un nombre? (5)
A menos que el código esté haciendo algo inusual, como actualizar directamente los globales , el código fuente debe indicar de dónde proviene cada variable:
x = 10 # Assigned in the current module
from random import randrange # Loaded from random
from functools import * # Loads everything listed in functools.__all__
En un programa de Python, si existe un nombre en el espacio de nombres del programa, ¿es posible averiguar si el nombre se importa desde algún módulo y, en caso afirmativo, de qué módulo se importa?
Algunos objetos (pero lejos de todo) tienen un atributo __module__ .
Si, por algún motivo, la fuente no está disponible, puede usar getmodule
de inspect
que hace todo lo posible para encontrar el módulo, agarrando __module__
si existe y luego __module__
a otras alternativas.
Si todo va bien, recuperas un objeto de módulo. A partir de eso, puede tomar __name__
para obtener el nombre real del módulo:
from inspect import getmodule
from collections import OrderedDict
from math import sin
getmodule(getmodule).__name__
''inspect''
getmodule(OrderedDict).__name__
''collections''
getmodule(sin).__name__
''math''
Si no encuentra nada, devuelve None
por lo que tendrías que hacerlo en este caso especial. En general, esto encapsula la lógica para usted, por lo que no necesita escribir una función para capturar realmente __module__
si existe.
Esto no funciona para objetos que no tienen esta información adjunta. Usted puede, como una caída, intentar y pasar el tipo para evitarlo:
o = OrderedDict()
getmodule(o) # None
getmodule(type(0)).__name__ # ''collections''
pero eso no siempre dará el resultado correcto:
from math import pi
getmodule(type(pi)).__name__
''builtins''
También puede ver globals()
, generará un dictado con todos los nombres que python usa, PERO también la variable, los módulos y las funciones que declaró dentro del espacio de nombres.
>>> x = 10
>>> import os
>>> globals() # to big to display here but finish with
# {... ''x'': 10, ''os'': <module ''os'' from ''/usr/local/lib/python2.7/os.py''>}
Por lo tanto, puedes probar si la variable fue declarada así:
if globals()[''x'']:
print(''x exist'')
try:
print(globals()[''y''])
except KeyError:
print(''but y does not'')
# x exist
# but y does not
Funciona también con módulos:
print(globals()[''os'']) # <module ''os'' from ''/usr/local/lib/python2.7/os.py''>
try:
print(globals()[''math''])
except KeyError:
print(''but math is not imported'')
# <module ''os'' from ''/usr/local/lib/python2.7/os.py''>
# but math is not imported
Puede ver en qué módulo se ha definido una función a través del atributo __module__
. De la documentación del modelo de datos de Python en __module__
:
El nombre del módulo en el que se definió la función, o Ninguno si no está disponible.
Ejemplo:
>>> from re import compile
>>> compile.__module__
''re''
>>> def foo():
... pass
...
>>> foo.__module__
''__main__''
>>>
El modelo de datos más adelante menciona que las clases también tienen el mismo atributo:
__module__
es el nombre del módulo en el que se definió la clase.
>>> from datetime import datetime
>>> datetime.__module__
''datetime''
>>> class Foo:
... pass
...
>>> Foo.__module__
''__main__''
>>>
También puede hacer esto con nombres incorporados como int
y list
. Puedes builtins
ellos desde el módulo builtins
.
>>> int.__module__
''builtins''
>>> list.__module__
''builtins''
>>>
Puedo usar
int
ylist
sinfrom builtins import int, list
. Entonces, ¿cómoint
ylist
están disponibles en mi programa?
Eso es porque int
y list
son nombres incorporados. No es necesario que los importe de forma explícita para que Python pueda encontrarlos en el espacio de nombres actual. Puede ver esto por sí mismo en el código fuente de la máquina virtual CPython . Como se mencionó @ user2357112, se accede a los nombres incorporados cuando falla la búsqueda global. Aquí está el fragmento relevante:
if (v == NULL) {
v = PyDict_GetItem(f->f_globals, name);
Py_XINCREF(v);
if (v == NULL) {
if (PyDict_CheckExact(f->f_builtins)) {
v = PyDict_GetItem(f->f_builtins, name);
if (v == NULL) {
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, name);
goto error;
}
Py_INCREF(v);
}
else {
v = PyObject_GetItem(f->f_builtins, name);
if (v == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError))
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, name);
goto error;
}
}
}
}
En el código anterior, CPython primero busca un nombre en el ámbito global. Si eso falla, entonces retrocede e intenta obtener el nombre de una asignación de nombres incorporados en el objeto de marco actual que se está ejecutando. Eso es lo que f->f_builtins
es.
Puedes observar esta asignación desde el nivel de Python usando sys._getframe()
:
>>> import sys
>>> frame = sys._getframe()
>>>
>>> frame.f_builtins[''int'']
<class ''int''>
>>> frame.f_builtins[''list'']
<class ''list''>
>>>
sys._getframe()
devuelve el marco en la parte superior de la pila de llamadas. En este caso, es el marco para el alcance del módulo. Y como puede ver desde arriba, la asignación de f_builtins
para el marco contiene las clases int
y list
, por lo que Python ha hecho que esos nombres estén disponibles para usted automáticamente. En otras palabras, es "construido" en el ámbito; De ahí el término "builtins" .