Live data from Hacker News

PEP 810 – Explicit lazy imports

peps.python.org

211–220 of 247 posts

Re: PEP 810 – Explicit lazy imports

#211

This is the wrong syntax, comparable to how "u" strings were the wrong syntax and "b" strings are the right syntax. They make that, what should be the default, a special case. Soon, every new code will use "lazy". The long term effect of such changes is a verbose language syntax. They should have had a period where one, if they want lazy imports, has to do "from __future__ import lazy_import". After that period, lazy…

I think your assessment of what's "the right/wrong" syntax is fair. But the transition you describe takes a long time, even now that the community has figured out a "deprecation cycle" process that seems satisfactory (i.e. won't lead to another Python 3.0 situation).

> All which authors of old code would have to do is run a provided fix script in the root directory of their code.

As I recall, `lib2to3` didn't do a lot to ease tensions. And `six` is still absurdly popular, mainly thanks to `python-dateutil` still attempting to support 2.7.

Re: PEP 810 – Explicit lazy imports

#212
post #166

Given all the problems people are mentioning, it seems like this proposal is on the wrong side. There should be an easy way for a module to declare itself to be lazy loaded. The module author, not the user, is the one who knows whether lazy loading will break stuff.

> There should be an easy way for a module to declare itself to be lazy loaded.

It can just implement lazy loading itself today, by using module-level __getattr__ (https://docs.python.org/3/reference/datamodel.html#customizi...) to overwrite itself with a private implementation module at the appropriate time. Something like:

  # foo.py
  def __getattr__(name):
      # clean up the lazy loader before loading
      # this way it's cleaned up if the implementation doesn't replace it,
      # and not scrubbed if it does
      global __getattr__
      del __getattr__
      import sys
      self = sys.modules[__name__]
      from . import _foo
      # "star-import" by adding names that show up in __dir__
      self.__dict__.update(**{k: getattr(_foo, k) for k in _foo.__dir__()})
      # On future attribute lookups, everything will be in place.
      # But this time, we need to delegate to the normal lookup explicitly
      return getattr(self, name)
Genericizing this is left as an exercise.

Re: PEP 810 – Explicit lazy imports

#213

This would be a huge deal for Python startup time *if* it was applied to all the standard library packages recursively. Right now importing asyncio brings in half the standard library through transitive imports.

It's bad, but it's not that bad.

  $ time python -c '' # baseline

  real 0m0.020s
  user 0m0.015s
  sys 0m0.005s

  $ time python -c 'import sys; old = len(sys.modules); import asyncio; print(len(sys.modules) - old)'
  104

  real 0m0.076s
  user 0m0.067s
  sys 0m0.009s
For comparison, with the (seemingly optimized) Numpy included with my system:

  $ time python -c 'import sys; old = len(sys.modules); import numpy; print(len(sys.modules) - old)'
  185

  real 0m0.124s
  user 0m0.098s
  sys 0m0.026s

Re: PEP 810 – Explicit lazy imports

#214

Kinda related, I wish there was an easy way to exclude dependencies at pip-install time and mock them at runtime so an import doesn't cause an exception. Basically a way for me to approximate "extras" when the author isn't motivated to do it for me, even though it'd be super brittle.

This sounds doable, actually. You'd want to pre-install (say, from a local wheel) a matching dummy dependency where the metadata claims that it's the right version of whatever package (so the installer will just see that the dependency is "already satisfied" and skip it), but the actual implementation code just exposes a hook to your mocking system.

Doesn't work if version resolution decides to upgrade or downgrade your installed package, so you need to make sure the declared version is satisfactory, too.

Re: PEP 810 – Explicit lazy imports

#215

Earlier quoted context omitted.

I also hope this proposal succeeds, but I'm not optimistic. This will break tons of code and introduce a slew of footguns. Import statements fundamentally have side effects, and when and how these side effects are applied will cause mysterious breakages that will keep people up for many nights. This is not fearmongering. There is a reason why the only flavor of Python with lazy imports comes from Meta, which is one o…

They are not entitled to hold the opinion that their imports takes too long, if they dont know the inner workings of pythons import system? Do you listen to yourself?

Nothing wrong with that statement.

Right now in python, you can move import statement inside a function. Lazy imports at top level are not needed. All lazy imports do is make you think less about what you are writing. If you like that, then just vibe code all of your stuff, and leave the language spec alone.

Re: PEP 810 – Explicit lazy imports

#216
post #62
post #32

Love this. My https://llm.datasette.io/ CLI tool supports plugins, and people were complaining about really slow start times even for commands like "llm --help" - it turned out there were popular plugins that did things like import pytorch at the base level, so the entire startup was blocked on heavy imports. I ended up adding a note to the plugin author docs suggesting lazy loading inside of functions - https://llm.…

You can implement this from your tool today: https://news.ycombinator.com/item?id=45467489 Note that this is global to the entire process, so for example if you make an import of Numpy lazy this way, then so are the imports of all the sub-modules. Meaning that large parts of Numpy might not be imported at all if they aren't needed, but pauses for importing individual modules might be distributed unpredictably across…

Is it another potential solution (until PEP 810 is accepted) to override the NameError exception, decide if it was triggered by an unloaded package from a list, and then running again that line of code? I understand the inefficiency of this solution (e.g. the same line could trigger NameError several times and you need to run it again until all modules are loaded) but this is a good brainstorming thread.

Re: PEP 810 – Explicit lazy imports

#217
post #32

Love this. My https://llm.datasette.io/ CLI tool supports plugins, and people were complaining about really slow start times even for commands like "llm --help" - it turned out there were popular plugins that did things like import pytorch at the base level, so the entire startup was blocked on heavy imports. I ended up adding a note to the plugin author docs suggesting lazy loading inside of functions - https://llm.…

Parse the command line and do things like "--help" without doing the imports. Only do imports when you know you need them -- or as an easy approximation, only if the easy command line options have been handled and there's still something to do.

Or require plugins to be competently written.

Bad performing third party plugins are user error.

Re: PEP 810 – Explicit lazy imports

#218
post #197

Earlier quoted context omitted.

What do you do today to resolve a dependency conflict when an intermediate library has a just-so dependency tree? The charitable interpretation of this proposed feature is that it would handle this case exactly as well as the current situation, if the situation isn't improved by the feature. This feature says nothing about the automatic installation of libraries. This feature is absolutely not about supporting multip…

> What do you do today to resolve a dependency conflict when an intermediate library has a just-so dependency tree? When an installer resolves dependency conflicts, the project code isn't running. The installer is free to discover new constraints on the fly, and to backtrack. It is in effect all being done "statically", in the sense of being ahead of the time that any other system cares about it being complete and co…

> and support having multiple simultaneous versions of any Python library installed.

Installed. Not loaded.

The reason is to do away with virtual environments.

I just want to say `import numpy@2.3.x as np` in my code. If 2.3.2 is installed, it gets loaded as the singleton runtime library. If it's not installed, load the closest numpy available and print a warning to stderr. If a transient dependency in the runtime tree wants an incompatible numpy, tough luck, the best you get is a warning message on stderr.

You already have the A, B, C dependency resolution problem you describe today. And if it's not caught at the time of installing your dependencies, you see the failure at runtime.

Re: PEP 810 – Explicit lazy imports

#219

Lazy imports have been proposed before, and were rejected most recently back in 2022: https://discuss.python.org/t/pep-690-lazy-imports-again/1966... . If I recall correctly, lazy imports are a feature supported in Cinder, Meta's version of CPython, and the PEP was driven by folks that worked on Cinder. Last time, a lot of the discussion centered around questions like: Should this be opt-in or opt-out? At what level?…

I also hope this proposal succeeds, but I'm not optimistic. This will break tons of code and introduce a slew of footguns. Import statements fundamentally have side effects, and when and how these side effects are applied will cause mysterious breakages that will keep people up for many nights. This is not fearmongering. There is a reason why the only flavor of Python with lazy imports comes from Meta, which is one o…

This is a new syntax, so it is opt-in. The new syntax can be conceived as syntax sugar that lets you rewrite

  def my_func():
      import my_mod
      my_mod.do_stuff()
as

  lazy import my_mod
  def my_func():
      my_mod.do_stuff()

Ie, with lazy, the import happens at the site of usage. Since clearly this is code that could already be written, it only breaks things in the sense that someone could already write broken code. Since it is opt in, if using it breaks some code, then people will notice that and choose not to rewrite that code using it.

Re: PEP 810 – Explicit lazy imports

#220
It would be interesting if instead you added a syntax whereby a module could declare that it supported lazy importing. Maybe even after running some code with side effects that couldn't be done lazily. For one thing, this would have a much broader performance impact, since it would benefit all users of the library, not just those who explicitly tagged their imports as lazy. For another, it would minimize breakage, since a module author knows best whether, and which parts of, their module can be lazily loaded.

On the other hand, it would create confusion for users of a library when the performance hit of importing a library was delayed to the site of usage. They might not expect, for example, a lag to occur there. I don't think it would cause outright breakage, but people might not like the way it behaved.

Post reply on HN