
I basically agree with many of your points. I have to admit that I am likely to be biased from my view, since I got hindered by the current behavior in that scenario. As you correctly stated,
import module from module import name assert name is module.name
and
from module import spam from module import eggs
things can become confusing, especially if you are reading the code as a third person that doesn't know someone might have added stuff to path resulting into this conflict. Actually I am surprised that someone actually things it through that far and comes up out of the nothing with those examples. Makes me already a bit happy ;) However, I don't see where
# Support many different versions of Python, or old versions # of the module, or drop-in replacement of the module. try: from module import name except ImportError: from fallback_module import spam as name
might change a actual thing. Case 1: Lets say "module" does not exist -> both fail Case 2: Exactly one "module" exists but it does not contain "name" -> both fail Case 3: Multiple "module" exist. At least one having "name" inside - Current Variant suceeds if and only if the first touched "module" does contain "name", otherwise fail - Proposed Variant will fail if and only if NO "module" at all contains "name" --> Why the first variant would be anyhow more correct than the second? A later module could have the "name" which you actually wanted, but you don't load it and falsly do a fallback Still, I see in sum that this at best is a trade-off, which one could argue pros and cons. So lets take a step back and maybe agree that the "shadowing" behaviour may come in unexpected also. The thing I made (which I right now changed completely thanks to the discussions to a setup.py X pip install -e solution that basically solves it) other people will do also. Given you're not too familiar with development installs or python setup at all, this is a thing you might not even know of or see as an unneeded obstacle. Hence, you will do some supposedly straight-forward thing like making your libs available in path. On top you might not even know that some dependency of a dependencies dependency might shadow your imports at all or tempers also with the path on its own. To conclude that, without changing the behaviour, Python might at least recognize such a shadowing case and spill out a warning if something shadows something else (Like "Unreachable module") since it obviously could find it out for example with your proposed import algorithm variant. Someone then could actually google it, find the reasoning and would stumple about ways to fix his/her presumably bad practice. Thanks anyways for taking the time thinking through the implications clarifying your points! Am 29.10.2019 um 23:41 schrieb Steven D'Aprano:
Yes :)
That looks similiar to my problem, which i fixed for the moment of writing by renaming one folder. Basically, I would prefer if Python would not treat nth-level import fails different than first-level fails. I think you mean that you would prefer if Python *would* treat nth-level import failures differently. If the first level fails, the import search stops immediately and raises; you want the import search to continue if
On Tue, Oct 29, 2019 at 01:26:36PM -0000, mereep@gmx.net wrote: the second level fails.
Might seem like a small thing, but in my opinion it would: - keep the behaviour straight forward - Correct the error messages, since from the perspective of the user the import actually DOES exist - Does not break anything currently working - Makes me happy ;) I disagree with all but the last.
Think about the behaviour of ``from module import name`` in pure Python. Currently, it is straightforward to explain:
try to import module, or fail if it doesn't exist; name = module.name, or fail if the name doesn't exist.
With your behaviour, it becomes something complicated:
try to import module, or fail if it doesn't exist; remember where we are in the module import search path; try to set name = module.name; if that succeeds, return; else go back to line 1, but picking up the search from where we left off.
Re your point 2, I'm a user, and from my perspective, if module.name doesn't exist in the first module found, then it doesn't exist until I move or rename one of the clashing modules. That's how shadowing works, and I like it that way because it makes it easy to reason about what my code will do.
But the critical point is #3. Any change in behaviour could break working code, and this could too:
# Support many different versions of Python, or old versions # of the module, or drop-in replacement of the module. try: from module import name except ImportError: from fallback_module import spam as name
Same for the similar idiom:
try: from module import name except ImportError: def name(arg): # re-implement basic version as a fallback
I use those two idioms frequently. The last thing I want is for the behaviour of import to change, which would potentially change the behaviour above from what's tested and works to something which might pick up *the wrong module* from what I'm expecting it to pick up.
You are asking us to change the behaviour of import in the case of shadowing, to support a use-case which is (in my, and probably most peoples, opinion) very poor practice. That has some pretty surprising consequences:
from module import spam from module import eggs
You would expect that spam and eggs both come from the same module, right? Surprise! No they don't, with your proposal they might come from different modules. That's going to play havok with debugging.
import module from module import name assert name is module.name
You would expect that assertion to be true, right? (Importing doesn't copy objects.) Surprise! The assertion can raise AttributeError: module.name might not exist even if ``from module import name`` succeeds.
I expect that with a bit more thought I could come up with some more scenarios where the behaviour of Python programs could change in very surprising ways.
So I will argue against this proposed change.