Al importar el paquete instalado desde el script surge "AttributeError:el módulo no tiene ningún atributo" o "ImportError:no puede importar el nombre".

python exception python-module shadowing


Tengo un script llamado requests.py que importa el paquete de solicitudes. El script no puede acceder a los atributos del paquete o no puede importarlos. ¿Por qué esto no funciona y cómo lo soluciono?

El siguiente código genera un AttributeError .

import requests

res = requests.get('http://www.google.ca')
print(res)
Traceback (most recent call last):
  File "/Users/me/dev/rough/requests.py", line 1, in <module>
    import requests
  File "/Users/me/dev/rough/requests.py", line 3, in <module>
    requests.get('http://www.google.ca')
AttributeError: module 'requests' has no attribute 'get'

El siguiente código genera un ImportError .

from requests import get

res = get('http://www.google.ca')
print(res)
Traceback (most recent call last):
  File "requests.py", line 1, in <module>
    from requests import get
  File "/Users/me/dev/rough/requests.py", line 1, in <module>
    from requests import get
ImportError: cannot import name 'get'

O código que importa desde un módulo dentro del paquete de requests :

from requests.auth import AuthBase
Traceback (most recent call last):
  File "requests.py", line 1, in <module>
    from requests.auth import AuthBase
  File "/Users/me/dev/rough/requests.py", line 1, in <module>
    from requests.auth import AuthBase
ImportError: No module named 'requests.auth'; 'requests' is not a package




Answer 1 idjaw


Esto sucede porque su módulo local llamado requests.py sombrea el módulo de requests instalado que está tratando de usar. El directorio actual se antepone a sys.path , por lo que el nombre local tiene prioridad sobre el nombre instalado.

Un consejo extra de depuración cuando esto surja es mirar el Traceback cuidadosamente,y darse cuenta de que el nombre de su script en cuestión coincide con el módulo que está tratando de importar:

Fíjate en el nombre que usaste en tu guión:

File "/Users/me/dev/rough/requests.py", line 1, in <module>

El módulo que está intentando importar: requests

Cambie el nombre de su módulo por otro para evitar la colisión de nombres.

Python puede generar un requests.pyc archivo al lado de su requests.py archivo (en el __pycache__ directorio en Python 3). Elimine eso también después de cambiarle el nombre, ya que el intérprete aún hará referencia a ese archivo y volverá a generar el error. Sin embargo, el archivo pyc en __pycache__ no debería afectar su código si el archivo py se ha eliminado.

En el ejemplo, cambiar el nombre del archivo a my_requests.py , la eliminación de requests.pyc , y funcionando de nuevo con éxito impresiones <Response [200]> .




Answer 2 Dave Rove


Para el escritor de la pregunta original, y para aquellas personas que buscan en la cadena "AttributeError: el módulo no tiene atributo", la explicación común según la respuesta aceptada, es que un script creado por el usuario tiene un choque de nombres con una biblioteca nombre del archivo. Sin embargo, tenga en cuenta que el problema podría no estar en el nombre del script que genera el error (como ocurrió en el caso anterior), ni en ninguno de los nombres de los módulos de la biblioteca importados explícitamente por ese script. Puede tomar un poco de trabajo de detective descubrir qué archivo está causando el problema.

Como ejemplo para ilustrar el problema, imagine que está creando una secuencia de comandos que utiliza la biblioteca "decimal" para cálculos precisos de coma flotante con números decimales, y nombra su secuencia de comandos " mydecimal.py " que contiene la línea " import decimal " . No hay ningún problema con nada de eso, pero encuentra que genera este error:

AttributeError: 'module' object has no attribute 'Number'

Esto sucedería si previamente hubiera escrito un script llamado " numbers.py " porque la biblioteca "decimal" llama a los "números" de la biblioteca estándar, pero en su lugar encuentra su script anterior. Incluso si hubiera eliminado eso, podría no terminar el problema porque Python podría haberlo convertido en bytecode y haberlo almacenado en un caché como " numbers.pyc ", por lo que también tendría que buscarlo.