2015-10-19 11 views
5

Ho osservato il seguente comportamento in Python 3.4.2 e non riesco a spiegarlo. Speriamo che qualcuno potrebbe fare luce sulla questione:import urllib.parse fallisce quando Python viene eseguito dalla riga di comando

In IPython:

In [129]: import urllib 

In [130]: print(urllib.parse) 
<module 'urllib.parse' from '/Users/ashwin/.pyenv/versions/3.4.2/lib/python3.4/urllib/parse.py'> 

ho importato un modulo, e stampato uno dei suoi attributi. Tutto funziona come previsto. Finora, la vita è buona.

Ora, mi fanno la stessa cosa dalla riga di comando:

$ python -c 'import urllib; print(urllib.parse)' 
Traceback (most recent call last): 
    File "<string>", line 1, in <module> 
AttributeError: 'module' object has no attribute 'parse' 

Dica che cosa ?! non è così che dovrebbe funzionare.
Ok, forse questo è un comportamento a livello di python; forse i moduli non vengono importati immediatamente quando si utilizza il flag -c. Proviamo un altro modulo:

$ python -c 'import datetime; print(datetime.datetime)' 
<class 'datetime.datetime'> 

Cosa ?! Come funziona per datetime e non per urllib? Sto usando la stessa versione di Python in entrambe le posizioni (3.4.2)

Qualcuno ha qualche idea su questo?

EDIT:

Per uno dei commenti:

$ which -a ipython 
/Users/ashwin/.pyenv/shims/ipython 
/Library/Frameworks/Python.framework/Versions/2.7/bin/ipython 
/usr/local/bin/ipython 
/usr/local/bin/ipython 

E

$ which -a python 
/Users/ashwin/.pyenv/shims/python 
/Library/Frameworks/Python.framework/Versions/2.7/bin/python 
/usr/bin/python 
/usr/bin/python 
+0

si consiglia di aggiungere l'output di 'che -a ipython' e' che -a python' – cel

+0

@cel: Non capisco come che avrebbe aiutato, ma ho aggiunto che – inspectorG4dget

+0

Così ' python -m IPython -c 'importa datetime; stampare (datetime.datetime) ''e' python -c' importare datetime; print (datetime.datetime) ''dai risultati diversi? – cel

risposta

3

Quando si esegue import urllib, si crea l'oggetto modulo del modulo urllib (che in realtà è un package) senza importare i suoi sottomoduli (analizzare, richiesta eccetera.).

È necessario che l'oggetto modulo genitore (urllib) si trovi nello spazio dei nomi se si desidera accedere al suo sottomodulo utilizzando l'accesso agli attributi. Oltre a questo, il sottomodulo deve essere già caricato (importato). Dalla documentation:

se la confezione spam ha un sottomodulo foo dopo aver importato spam.foo, spam avrà un attributo foo che è legato alla modulo. [...] Il mantenimento invariante è che se si dispone di sys.modules['spam'] e sys.modules['spam.foo'] (come si farebbe dopo l'importazione di cui sopra), quest'ultimo deve apparire come attributo foo del primo.

C'è solo un esempio di ciascun modulo, così eventuali modifiche apportate all'oggetto modulo urllib (memorizzato in sys.modules['urllib']) vengono riflessi ovunque.

Non importa urllib.parse, ma IPython fa. Per dimostrare questo ho intenzione di creare un file di avvio:

import urllib 
print('Running the startup file: ', end='') 
try: 
    # After importing 'urllib.parse' ANYWHERE, 
    # 'urllib' will have the 'parse' attribute. 
    # You could also do "import sys; sys.modules['urllib'].parse" 
    urllib.parse 
except AttributeError: 
    print("urllib.parse hasn't been imported yet") 
else: 
    print('urllib.parse has already been imported') 
print('Exiting the startup file.') 

e lanciare ipython

[email protected]:~$ ipython 
Running urllib/parse.py 
Running the startup file: urllib.parse has already been imported 
Exiting the startup file. 
Python 3.6.0a0 (default:089146b8ccc6, Sep 25 2015, 14:16:56) 
Type "copyright", "credits" or "license" for more information. 

IPython 4.0.0 -- An enhanced Interactive Python. 

E 'l'effetto collaterale di importazione pydoc durante l'avvio di IPython (which ipython è /usr/local/bin/ipython):

/usr/local/bin/ipython, line 7: 
    from IPython import start_ipython 
/usr/local/lib/python3.6/site-packages/IPython/__init__.py, line 47: 
    from .core.application import Application 
/usr/local/lib/python3.6/site-packages/IPython/core/application.py, line 24: 
    from IPython.core import release, crashhandler 
/usr/local/lib/python3.6/site-packages/IPython/core/crashhandler.py, line 28: 
    from IPython.core import ultratb 
/usr/local/lib/python3.6/site-packages/IPython/core/ultratb.py, line 90: 
    import pydoc 
/usr/local/lib/python3.6/pydoc.py, line 68: 
    import urllib.parse 

Questo spiega il motivo per cui il codice qui sotto non riesce - si importa solo urllib e niente sembra importare urllib.parse:

$ python -c 'import urllib; print(urllib.parse)' 

D'altra parte, le seguenti opere di comando perché datetime.datetime è non un modulo. È una classe che viene importata durante lo import datetime.

$ python -c 'import datetime; print(datetime.datetime)' 
+0

Ma se provo' pydoc' in IPython ottengo un 'NameError'.Ciò non significa che 'pydoc' non è stato importato da IPython all'avvio? – inspectorG4dget

+1

@ inspectorG4deposito * è * stato importato, è possibile verificare se è già in ['sys.modules'] (https://docs.python.org/3/library/sys.html#sys.modules):' ' pydoc 'in sys.modules' restituisce 'True'. Devi solo importarlo nello spazio dei nomi corrente. – vaultah

+0

Ok, ma 'urllib' non si trova nello spazio dei nomi corrente O in 'sys.modules' in IPython. Quindi non sono ancora chiaro su come 'urllib.parse' esiste automagicamente nel namespace – inspectorG4dget

0

urllib.parse è disponibile da Python 3 in poi. Penso che potrebbe essere necessario import urllib.parse, non import urllib. Non sono sicuro se (quando) l'importazione del sottomodulo sia implicita.

Direi che IPython importa urllib.parse all'avvio ed è per questo che è disponibile.

parse è un modulo non un attributo:

Python 3.4.2 (default, Oct 15 2014, 22:01:37) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import urllib 
>>> urllib.parse 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'module' object has no attribute 'parse' 
>>> import urllib.parse 
>>> urllib.parse 
<module 'urllib.parse' from '/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/urllib/parse.py'> 
+1

L'analisi sembra errata, dato che sto usando python3.4.2 anche quando chiamo 'python' dalla riga di comando. Come visto nei miei percorsi, la prima voce proviene da 'pyenv', che attualmente sta puntando alla v3.4.2 – inspectorG4dget

+0

Provate' import urllib.parse' invece di 'import urllib' come suggerito. –

+0

Anche grazie per il chiarimento del percorso. Ho aggiornato la domanda e rimosso i bit che non erano corretti. –

Problemi correlati