On Aug 13, 2019, at 15:01, Eric V. Smith email@example.com wrote:
On 8/13/2019 5:49 PM, Andrew Barnert via Python-ideas wrote: But I think the lazy-import-decimal-on-first-dump-with-use_decimal solves that, and solves it even better than __json__, even besides the fact that it’s a better API than exposing “dump raw text into any JSON, and it’s up to you to get it right”. No import time if you’re not using it, just setting a global to None. Even if you are using it, the cost of importing it from the sys.modules cache is pretty tiny. (After all, you won’t have any Decimal objects without having imported decimal, unless you do some nasty tricks—at which point monkeypatching json to fake the import isn’t any nastier.)
dataclasses does something similar: it wants to know if something is a typing.ClassVar, but it doesn't want to import typing to find out. So it has:
typing = sys.modules.get('typing') if typing: if (_is_classvar(a_type, typing) or (isinstance(f.type, str) and _is_type(f.type, cls, typing, typing.ClassVar, _is_classvar))):
That’s clever, but I don’t think it’s actually needed here. We can just do the usual lazy import thing: set it to None, and then when we need it (whenever you construct a JSONEncoder object with use_decimal*), if it’s None, import it. That will automatically use the sys.modules cache anyway, and it only costs a few extra nanoseconds, and we only do it once in your entire program. Surely it’s not worth optimizing away a few ns one time in exchange for making every single test more complicated, and probably slower?
What I was referring to in the parens was that it is technically possible to get objects that would pass isinstance(decimal.Decimal) except that decimal isn’t in sys.modules, but I don’t think we have to worry about that. For example, anyone who uses importlib to get decimal imported into a local that’s not stored in the cache ought to know how to monkeypatch json.decimal = my_secret_decimal_import if they want to avoid the cost of a second import.
* If you’re worried about the None test on each JSONEncoder construction where use_decimal, given that every call to dump or dumps constructs an encoder, consider this: that construction takes microseconds, and adding a None test makes about an 0.1% difference. Anyone who’s dumping zillions of objects to JSON already has to explicitly construct and reuse an encoder, so that extra cost only happens once in their program.