News for hackers. Stuff that matters.
Re:PEP 810 – Explicit lazy imports by sedatk on Friday October 03, 2025 @03:06PM (#45466575)
I wonder how much things would break if all imports were lazy by default.
Re:PEP 810 – Explicit lazy imports by ashu1461 on Friday October 03, 2025 @04:13PM (#45467276)
There will be chaos, all code bases usually have tons of side effects.
Re:PEP 810 – Explicit lazy imports by simlevesque on Friday October 03, 2025 @03:09PM (#45466614)
Maybe nothing would break ?

edit: ok well "xxx in sys.modules" would indeed be a problem

Re:PEP 810 – Explicit lazy imports by IshKebab on Friday October 03, 2025 @03:13PM (#45466651)
Yeah unfortunately in real world Python code people put side effects in their modules all the time.
Re:PEP 810 – Explicit lazy imports by kstrauser on Friday October 03, 2025 @03:25PM (#45466782)
In Python? I almost never see that. And I’ve certainly never signed off on a PR that did that.
Re:PEP 810 – Explicit lazy imports by oofbey on Friday October 03, 2025 @03:35PM (#45466896)
Maybe your code is awesome, but you're almost certainly using a library which does it.
Re:PEP 810 – Explicit lazy imports by lyu07282 on Friday October 03, 2025 @04:28PM (#45467425)
This. The most egregious example I've ever seen is the inflect library, takes almost 2 seconds(!) to import: https://github.com/jaraco/inflect/issues/212
Re:PEP 810 – Explicit lazy imports by zahlman on Friday October 03, 2025 @04:57PM (#45467697)
Recursively importing other modules is itself a side effect.

In fact, all the code you see in the module is "side effects", in a sense. A `class` body, for example, has to actually run at import time, creating the class object and attaching it as an attribute of the module object. Similarly for functions. Even a simple assignment of a constant actually has to run at module import. And all of these things add up.

Further, if there isn't already cached bytecode available for the module, by default it will be written to disk as part of the import process. That's inarguably a side effect.

Re:PEP 810 – Explicit lazy imports by flykespice on Friday October 03, 2025 @08:54PM (#45469513)
Side-effect means you're changing state outside the scope the code is running.

Sure thing you can declare globals variable and run anything on a module file global scope (outside funcs and class body), but even that 'global' scope is just an illusion, and everything declared there, as yourself said, is scoped to the module's namespace

(and you can't leak the 'globals' when importing the module unless you explicity do so 'from foo import *'. Think of python's import as eval but safer because it doesn't leaks the results from the module execution)

So for a module to have side-effect (for me) it would either:

- Change/Create attributes from other modules

- Call some other function that does side-effect (reflection builtins? IO stuff)

Re:PEP 810 – Explicit lazy imports by IshKebab on Saturday October 04, 2025 @07:34AM (#45472558)
Often it's things like registering functions in a global registry, or patching things about how Python works (e.g. adding stuff to the module path).
Re:PEP 810 – Explicit lazy imports by kstrauser on Saturday October 04, 2025 @07:44AM (#45472617)
You’re right. “Side effect” here means that your program’s behavior changes simply by importing something, eg by monkey patching something else.

If’s not:

* Importing other modules.

* Taking a long time to import.

* Writing .pyc files.

If any program can “import foo” and still execute exactly the same bytecode afterward as before, you can say that foo doesn’t have side effects.

Re:PEP 810 – Explicit lazy imports by eesmith on Friday October 03, 2025 @03:30PM (#45466842)
All my code which uses import probing would fail, such as fallbacks:

  try:
    import module
  except ImportError:
    import slow_module as module
Conditional support testing would also break, like having tests which only run if module2 is available:

  try:
    import module2
  except ImportError:
    def if_has_module2(f):
      return unittest.skip("module2 not available")(f)
  else:
    def if_has_module2(f):
      return f

  @if_has_module2
  class TestModule2Bindings(....
The proto-PEP also gives an example of using

  with suppress_warnings():
    import module3
where some global configuration changes only during import.

In general, "import this" and "import antigravity" - anything with import side-effects - would stop working.

Oh, and as the proto-PEP points out, changes to sys.path and others can cause problems because of the delay between time of lazy import and time of resolution.

Then there's code where you do a long computation then make use of a package which might not be present.

  import database  # remember to install!!
  import qcd_simulation

  universe = qcd_simulation.run(seconds = 30*24*60*60)
  database.save(universe)

All of these would be replaced with "import module; module.__name__" or something to force the import, or by an explicit use to __import__.
Re:PEP 810 – Explicit lazy imports by npage97 on Friday October 03, 2025 @04:06PM (#45467216)
You have to opt in with the lazy import keyword no matter what. This pep also prevents lazy import in try catch. I think your concern matters if ‘module’ itself has a lazy import that you want to check exists. With this you now need to be more rigorous in check those sub dependencies.

This can already happen with non top level imports so it is not a necessarily a new issue, but could become more prevalent if there is an overall uptake in this feature for optional dependencies.

Re:PEP 810 – Explicit lazy imports by eesmith on Friday October 03, 2025 @04:55PM (#45467671)
My post was a response to the sedatk conjectural "I wonder how much things would break if all imports were lazy by default."

I have zero concerns about this PEP and look forward to its implementation.

Re:PEP 810 – Explicit lazy imports by zahlman on Friday October 03, 2025 @05:01PM (#45467721)
With the LazyLoader technique I described at https://news.ycombinator.com/item?id=45467489 , there is no problem:

  >>> import nonexistent_module
  Traceback (most recent call last):
    File "<python-input-2>", line 1, in <module>
      import nonexistent_module
    File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
    File "<frozen importlib._bootstrap>", line 1322, in _find_and_load_unlocked
    File "<frozen importlib._bootstrap>", line 1262, in _find_spec
    File "<python-input-0>", line 8, in find_spec
      base.loader = LazyLoader(base.loader)
                               ^^^^^^^^^^^
  AttributeError: 'NoneType' object has no attribute 'loader'
The implementation should probably convert that exception back to ImportError for you, but the point is that the absence of an implementation can still be detected eagerly while the actual loading occurs lazily.
Re:PEP 810 – Explicit lazy imports by eesmith on Friday October 03, 2025 @05:29PM (#45468012)
Ahh, so you do the find first, and keep that around before loading.

I have bad memories of using a network filesystem where my Python app's startup time was 5 or more seconds because of all the small file lookups for the import were really slow.

I fixed it by importing modules in functions, only when needed, so the time went down to less than a second. (It was even better using a zipimport, but for other reasons we didn't use that option.)

If I understand things correctly, your code would have the same several-second delay as it tries to resolve everything?

Re:PEP 810 – Explicit lazy imports by zahlman on Friday October 03, 2025 @05:46PM (#45468176)
Yes, if checking for a file is slow, then checking for a file is slow. If you need to know up front whether the module exists, then you can't get around using the "figure out whether the module exists" machinery up front. And if the definition of "a module exists" includes cases where the module is represented by a file whose existence you have to check for, then there's no getting around that, either.

(Trying to do "fallback" logic with lazily-loaded modules is also susceptible to race conditions, of course. What if someone defines the module before you try to use it?)