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/