On Sat, 9 Apr 2022 at 00:34, Steven D'Aprano <st...@pearwood.info> wrote: > > On Tue, Apr 05, 2022 at 02:17:00PM +1000, Chris Angelico wrote: > > > Do you ever have one module that's using statute miles and > > another that's using nautical miles, but *not both in the same > > module*? The only reason to have them namespaced to modules is to > > allow different modules to use them independently. If your application > > needs to use both statute and nautical miles in the same module (most > > likely the main module), then it's going to have an issue, and your > > proposal adds a ton of complexity (that's a real unit, by the way, I > > totally didn't make it up) for no benefit whatsoever. > > That's not the real problem. > > The real problem is that my program may: > > * import ham, which registers mile as 1609.3412 m > * import spam, which registers mile as 1609.344 m > * import cheese, which registers mile as 1609.3472 m > * import aardvark, which registers mile as 1609.3426 m > * import hovercraft, which registers mile as 1853.181 m > > and then do calculations in miles, before converting to metres, and the > results I get will be subtly (or not so subtly) different depending on > the order I import those modules. > > (By the way, none of the above are nautical miles; of which there are at > least three.)
Would it be better if you wrote it like this? import SI; si.register() I would be hard pressed to imagine a situation as pathological as you suggest. Aside from a (relatively small) number of common systems, most measurement systems are going to be sufficiently special purpose that they're going to be the entire application. If you have a library that chooses to register a common name like "mile", it's no different from that library doing something like "decimal.getcontext().prec = 2", which is a fully documented feature. Some features belong to the application, not the library, and I don't think that's spoiled other things before. We cope. > > What's the difference? You're looking at a fundamentally identical > > problem, and thinking that it's fundamentally solved by module-level > > separation? Show me some evidence. > > You are correct that this is fundamentally identical to the problem that > namespaces are designed to solve. This is why modern languages don't > have one single system-wide namespace. Right. Remind me why most command shells have a single system-wide namespace, then? Or is it a really good idea in programming but not in scripting? > We have 30+ years of Python programming, and 40-odd years of programming > prior to Python, showing that the solution to the name collusion problem > is to have distinct namespaces rather than one single system-wide > namespace that everything writes to. That's exactly my point. Yes. I have never disputed the value of namespaces as a way of stopping names from colluding. Or colliding. What I'm disputing is that the *module* is the one and only namespace that is right here. You haven't yet shown a single bit of evidence for that. > (Is that even possible? At import time, can eggs tell which module is > importing it?) I'm sure anything's possible with sys._getframe. > > Have you ever mutated sys.modules? > > Not directly, no, except by the approved method of calling `import`, > which never over-writes an existing entry, only adds new entries. It's an incredibly useful way to mock things. You provide a module before something else calls on it. (It's also a good way for a module to replace *itself*, although that's less commonly needed now that you can do module-level getattr.) > Nor have I ever mutated the central registry of codecs to *replace* > an existing encoder (like UTF-8) with my own. Likewise for error > handlers. Right. And, again, these namespaces are not per-module, yet you aren't bothered by someone registering a name that you want. Why is the module the perfect scope for units? > There's only a relatively small number of each, and the two registries > change so rarely that there is next to zero chance that I might > accidently trample over an existing codecs or error handler with my own. > And I do not expect that arbitrary imports will make changes to those > registries. You don't expect it. But somehow you DO expect arbitrary imports to mutate the unit namespace. Why? > With units, there are thousands of named units, with many name > collisions. The system would be unworkable with only a single > interpreter-wide registry. [citation needed] Do libraries tend to work in this way, giving unitted values in a system different from the one the application uses? Is that actually a thing, or are you just guessing? > > > This is exactly analogous to the situation Python would have if there > > > were no per-module globals, just the system-wide builtins, and every > > > library stored top-level variables and functions in that namespace. > > > *shudders* > > > > Straw man. It's more like using decimal.getcontext() and making > > changes. > > The situation is analogous, but not identical. The decimal context is > not a interpreter-wide registry of long-lasting entities intended to be > used by any and all modules. It is a per-thread part of the decimal API. It's an interpreter-wide registry of long-lasting settings that affect any and all modules that use decimals. And yes, it's per-thread, but given your long-seated fear of threads, I'm surprised you even consider that to be a difference. > Its not even a very close analogy: aside from sharing the vague concept > of "global state" with your units registry, there's nothing like > registering a unit ("furlongs per fortnight") in the decimal context. > There are only eight settings, and you cannot set arbitary attributes in > decimal contexts. So? You can most certainly mess up some other module that uses decimals. Any module you import could set the default context's precision to a really low value, which would mess up all kinds of things. Yet we do not fear this, because we expect that libraries won't do that. > Other modules (except possibly your application's main module) are not > expected to modify the current context, although that's not enforced. > (This is Python: you can shoot yourself in the foot if you really want > to.) It would be considered *badly-behaved* for other modules or > functions to directly modify the current decimal context instead of > using localcontext() to temporarily change the current context. Right. So, wouldn't it be equally ill-behaved for a module to randomly register units? Why is this different? Aside from those whose specific purpose is to be unit providers, libraries shouldn't be registering units. Otherwise they are behaving badly. I don't see this as any different from what we already have. > P.S. localcontext makes a copy of the context. Just sayin'. (By default) > But with your central, interpreter-wide registry of units, modules which > wish to use a named unit have no other choice than to register it with > the central registry. > > If my module aarvark.py wants to use a named unit, the pottle (a > historical measurement equal to 1/2 a British gallon), what can I do? Does it need that to be in the source code? The registry applies ONLY to source code (although, of course, it would also be a good place for parsers to look). > I can check the registry to see if pottle is already defined. If it > isn't, great, I can install it, and it will now be visible to every > module, whether they need it or not. > > But what if its already there, with a different value? Now I have only > two equally bad choices: > > 1. overwrite the system-wide pottle entry, breaking other modules; > > 2. or do without. 3. Use the unit in a non-source-code way. > Because the registry is system-wide, I cannot define my own pottle unit > without nuking other module's pottle unit. > Good. You shouldn't be defining your own pottle unless you are the application. Global settings belong to the application. Libraries shouldn't be calling os.chdir(), messing with the default Decimal context, or monkeypatching the Random module to give a fixed sequence of numbers, without the consent of the application. I don't see a problem here. ChrisA _______________________________________________ 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/YZHIADSJZ4SRJBAHH3BT4WTOLAKF5Y3S/ Code of Conduct: http://python.org/psf/codeofconduct/