On Oct 29, 2019, at 11:45, Richard Vogel <mer...@gmx.net> wrote:
>> What happens if you break this rule is exactly what you’re seeing. The way 
>> Python ensures that doing `import spam` twice results in the same spam 
>> module object (so your globals don’t all get duplicated) is by storing 
>> modules by qualified name in sys.modules. So if the same file has two 
>> different qualified names, it’s two separate modules.
> I got that. That explains the behaviour I got, where Enum-Entries suddenly 
> where unequal to the "same" Enum-Entries causing a crash. Which actually was 
> better than having this behaviour happening unseen and having the supposed 
> same thing multiple times. That would have resulted in two differen 
> EventQueues. Cannot imagine all the time I would have spent until I would 
> have realized having two of them suddenly ;)
> Is there a reasoning for that behavior of Python?
> 
I suspect this goes so far back into the mists of time that there’s no mailing 
list discussion or anything. But I can take a guess.

First, the real issue here is that it’s confusing to have the same module exist 
under two different names. Normally, the module spam.eggs and the module eggs 
shouldn’t be the same thing. Especially given that, unlike most objects in 
Python, modules know their qualified names, and actually _need_ to know them 
for things like pickle and multiprocessing to work. It would be misleading if 
you looked at the qualified name of spam.eggs and got back something other than 
"spam.eggs", and not just to human readers, but to code.

While there are rare occasions when you might want spam.eggs and eggs to be the 
same thing, there are also rare occasions when you might want the same source 
to import as two separate objects. And both are less common than doing it 
mistakenly. Since these are both rare, the One Obvious Way To Do each one ought 
to be something obviously unusual (manipulating sys.modules, or manually using 
importlib) that signals your unusual intention to your readers.

Although I suspect the actual reasoning is just that, because these are both 
rare use cases, nobody bothered to design the behavior around either of them; 
instead, they just went with the simplest implementation that handles the 
non-rare cases as intended, and then just documented what it does in the rare 
cases as the behavior. And then, in the years since then (especially at 3.0 and 
when the new import system was implemented a few versions later) nobody had a 
compelling reason to change the rules.

The biggest consequence is the case where script.py is a runnable script but 
also a module, and thanks to a circular import somewhere it ends up getting 
imported indirectly by itself, so you have modules named "__main__" and 
"script" built from the same source. That one actually comes up, because you 
don’t really have to break any rules for it to happen (circular imports are 
legal, and work fine in some cases, even if they’re confusing in general and 
don’t work in other cases and should usually be avoided), but it’s effectively 
the same problem you’re running into. People have actually made proposals to 
fix that in some way (whether to make it a detectable error, or to special-case 
things so sys.modules['script'] = sys.modules['__main__'] from the start, or 
something else), but I don’t think anyone’s come up with a proposal that 
everyone else liked. If you want to know more about how people think about this 
whole wider issue, maybe search for the proposals on that narrower one.
> Why a thing isn't equal when its physically the same thing, meaning the 
> checksum is the same or its the same absolute path or ....
> 
Some things in Python act like “values”, where there’s a notion of equality 
based on equal contents—int, str, tuple, namedtuple and dataclass types, etc. 
But most other things act like “objects”, where no object is equal to anything 
but itself. Sometimes it’s about implicit (especially mutable) state—two 
different file objects are never equal, even if they represent the same disk 
file with the same position. Sometimes it’s about needing to be able to create 
distinct things—two Enum members from different classes are never equal even if 
they have the same name and value, and two Enum classes are never equal even if 
they have exactly the same members. (Imagine if you had code that did different 
things with ForegroundColor and BackgroundColor objects, and then they 
magically became the same type when you added bright background colors.)

Would you really want two different modules to be the same just because they 
happened to have the same contents, or happened to get those contents by 
executing the same source? You definitely wouldn’t want them to be identical 
(imagine if a.py and b.py were empty, you did `import a; import b; a.spam=2; 
b.spam=3`, and a.spam was now 3.) And I don’t think you’d want two 
non-identical modules to be equal.

But of course their contents wouldn’t be equal, because even a module built 
from an empty .py file has some default attributes, including __name__, which 
will be different between a and b.

(As a side note, modules don’t always have an absolute path. The most common 
way to get a module is as a .py file in a directory on sys.path, but there are 
other ways—cached .pyc flies delivered without the .py file, extension modules, 
modules inside zip archives, even modules that use arbitrary custom finders to 
pull them off a web server or out of a database, or simulate hierarchy on top 
of a flat filesystem, or whatever. Some of these have a confusing path, some 
have no path at all. They do always have a loader spec, which could 
theoretically serve the same purpose. But modules don’t remember the loader 
spec used to load them. Plus, loader specs, unlike names, are a low-level 
detail that most Python developers probably never learn.)
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/B6DE5LGUZCZ4CAOAOE2LCO5YJDGO7EW4/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to