Wat doet from __future__ import absolute_import eigenlijk?

| | | | | | | | |

Ik heb beantwoord een vraag over absolute import in Python, waarvan ik dacht dat ik deze begreep op basis van de Python 2.5 changelog en bijbehorende PEP. Echter, bij het installeren van Python 2.5 en een poging om een voorbeeld te maken van het correct gebruiken van from __future__ import absolute_import, realiseer ik me dat de dingen niet zo duidelijk zijn.

Rechtstreeks uit de changelog die hierboven is gelinkt, dit verklaring vatte mijn begrip van de absolute importwijziging nauwkeurig samen:

Laten we zeggen dat je een pakketdirectory hebt zoals deze:

pkg/pkg/__init__.py pkg/main.py pkg/string.py 

Dit definieert een pakket met de naam pkg dat de pkg.main en bevat pkg.string submodules.

Beschouw de code in de main.py-module. Wat gebeurt er als het de instructie import string uitvoert? In Python 2.4 en eerder is het zal eerst in de directory van het pakket kijken om een relatieve import uit te voeren, vindt pkg/string.py, importeert de inhoud van dat bestand als de pkg.string module, en die module is gebonden aan de naam "string" in de namen van de pkg.main module tempo.

Dus ik heb deze exacte directorystructuur gemaakt:

$ ls -R .: pkg/ ./pkg: __init__.py main.py string .py 

__init__.py en string.py zijn leeg. main.py bevat de volgende code:

import string print string.ascii_uppercase 

Zoals verwacht, dit uitvoeren met Python 2.5 mislukt met een AttributeError:

$ python2.5 pkg/main.py Traceback (meest recente oproep als laatste): bestand "pkg/main.py", regel 2 , in <module> print string.ascii_uppercase AttributeError: "module" object heeft geen attribuut "ascii_uppercase" 

Maar verder in de 2.5 changelog vinden we dit (nadruk toegevoegd):

In Python 2.5 kun je het gedrag van import" omschakelen naar absolute import met behulp van een from __future__ import absolute_import-instructie. Dit gedrag van absoluut importeren wordt de standaard in een toekomstige versie (waarschijnlijk Python 2.7). Zodra absolute import de standaard is, zal import string altijd de versie van de standaardbibliotheek vinden.

Ik heb dus pkg/main2.py gemaakt, identiek aan main.py maar met de aanvullende toekomstige importrichtlijn. Het ziet er nu zo uit:

from __future__ import absolute_import import string print string.ascii_uppercase 

Dit uitvoeren met Python 2.5, echter... mislukt met een AttributeError:

$ python2.5 pkg/main2.py Traceback (meest recente oproep laatst): bestand "pkg/main2.py", regel 3, in < ;module> print string.ascii_uppercase AttributeError: "module" object heeft geen attribuut "ascii_uppercase" 

Dit is behoorlijk in tegenspraak met de bewering dat string importeren altijd zoek de std-lib-versie met absolute import ingeschakeld. Wat meer is, ondanks de waarschuwing dat absolute importen gepland zijn om het "nieuwe standaard"-gedrag te worden, heb ik hetzelfde probleem met zowel Python 2.7, met of zonder de __future__-richtlijn:

$ python2.7 pkg/main.py Traceback (meest recente oproep als laatste): bestand "pkg/main.py", regel 2, in <module> print string.ascii_uppercase AttributeError: object "module" heeft geen attribuut "ascii_uppercase" $ python2.7 pkg/main2.py Traceback (meest recente oproep laatst): bestand "pkg/main2.py", regel 3, in <module> print string.ascii_uppercase AttributeError: "module" object heeft geen attribuut "ascii_uppercase" 

evenals Python 3.5, met of zonder (ervan uitgaande dat de print-instructie in beide bestanden is gewijzigd):

$ python3.5 pkg/main.py Traceback (meest recente oproep laatst): bestand "pkg/main.py", regel 2, in <module> print(string.ascii_uppercase) AttributeError: module "string " heeft geen kenmerk "ascii_uppercase" $ python3.5 pkg/main2.py Trac eback (meest recente oproep als laatste): bestand "pkg/main2.py", regel 3, in <module> print(string.ascii_uppercase) AttributeError: module "string" heeft geen attribuut "ascii_uppercase" 

Ik heb andere varianten hiervan getest. In plaats van string.py heb ik een lege module gemaakt -- een map met de naam string die alleen een lege __init__.py bevat -- en in plaats daarvan om imports uit main.py uit te geven, heb ik cd"d to pkg en voer de import rechtstreeks uit vanuit de REPL. Geen van deze varianten (noch een combinatie van hen) veranderde de resultaten hierboven. Ik kan dit niet in overeenstemming brengen met wat ik heb gelezen over de __future__-richtlijn en absolute imports.

Het lijkt mij dat dit gemakkelijk te verklaren is door het volgende (dit komt uit de Python 2-documenten, maar dit statement blijft ongewijzigd in dezelfde documenten voor Python 3):

sys.path

(...)

Zoals geïnitialiseerd bij het opstarten van het programma, het eerste item van deze lijst, path[0], is de map met het script dat werd gebruikt om de Python-interpreter aan te roepen. y niet beschikbaar is (bijv. als de interpreter interactief wordt aangeroepen of als het script wordt gelezen uit standaardinvoer), is path[0] de lege tekenreeks, die Python doorverwijst naar het zoeken naar modules in de huidige map eerst.

Dus wat mis ik? Waarom doet de __future__-statement schijnbaar niet wat het zegt, en wat is de oplossing van deze tegenstrijdigheid tussen deze twee secties van de documentatie, evenals tussen beschreven en feitelijk gedrag?

Shop

Learn programming in R: courses

$

Best Python online courses for 2022

$

Best laptop for Fortnite

$

Best laptop for Excel

$

Best laptop for Solidworks

$

Best laptop for Roblox

$

Best computer for crypto mining

$

Best laptop for Sims 4

$

Latest questions

NUMPYNUMPY

psycopg2: insert multiple rows with one query

12 answers

NUMPYNUMPY

How to convert Nonetype to int or string?

12 answers

NUMPYNUMPY

How to specify multiple return types using type-hints

12 answers

NUMPYNUMPY

Javascript Error: IPython is not defined in JupyterLab

12 answers


Wiki

Python OpenCV | cv2.putText () method

numpy.arctan2 () in Python

Python | os.path.realpath () method

Python OpenCV | cv2.circle () method

Python OpenCV cv2.cvtColor () method

Python - Move item to the end of the list

time.perf_counter () function in Python

Check if one list is a subset of another in Python

Python os.path.join () method