urls tutorial template example desde cero python python-3.x debugging module namespaces

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 y list sin from builtins import int, list . Entonces, ¿cómo int y list 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" .