Skip to main content

More Imports! - Delayed importing

Project description

More Imports! - Delayed importing

A couple of methods to make late importing cleaner

Problem

Splitting code into modules is nice, but it can result in cyclic dependencies.

foos.py

from bars import bar

def foo():
    bar()

bars.py

from foos import foo

def bar():
    foo()

We are not concerned with the infinite recursion; this is only for demonstrating cyclic dependencies.

More Imports!

Solution: Use expect/export pattern

All your cyclic dependencies are covered with this one pattern: Break cycles by expecting a name in the first module, and let the second module export to the first when the value is available

foos.py

from mo_imports import expect

bar = expect("bar")

def foo():
    bar()

bars.py

from mo_imports import export
from foos import foo

def bar():
    foo()

export("bars", bar)

Benefits

  • every expect is verified to match with an export (and visa-versa)
  • using an expected variable before export raises an error
  • code is run only once, at module load time, not later
  • methods do not run import code
  • all "imports" are at the top of the file

Solution: Use delay_import

Provide a proxy which is responsible for import upon first use of the module variable.

foos.py

from mo_imports import delay_import
from bars import bar

bar = delay_import("bars.bar")

def foo():
    bar()

bars.py

from foos import foo

def bar():
    foo()

This is the cleanest, but it requires any of __call__, __getitem__, __getattr__ to be called. Sentinals, placeholders, and default values can not be imported this way

Other solutions

If you do not use mo-imports your import cycles can be broken using one of the following common patterns:

Bad Solution: Keep in single file

You can declare yet-another-module that holds the cycles

foosbars.py

    def foo():
        bar()

    def bar():
        foo()

but this breaks the code modularity

Bad Solution: Use end-of-file imports

During import, setup of the first module is paused while it imports a second. A bottom-of-file import will ensure the first module is mostly setup to be used by the second.

foos.py

def foo():
    bar()

from bars import bar

bars.py

def bar():
    foo()

from foos import foo

Linters do not like this pattern: You may miss imports, since these are hiding at the bottom.

Bad Solution: Inline import

Import the name only when it is needed

foos.py

def foo():
    from bars import bar
    bar()

bars.py

def bar():
    from foos import foo
    foo()

This is fine for rarely run code, but there is an undesirable overhead because import is checked everytime the method is run. You may miss imports because they are hiding inline rather than at the top of the file.

Bad Solution: Use the _late_import() pattern

When other bad solutions do not work work, then importing late is the remaining option

foos.py

from bars import bar

def foo():
    bar()

bars.py

foo = None

def _late_import():
    global foo
    from foos import foo
    _ = foo

def bar():
    if not foo:
        _late_import()
    foo()

Placeholders variables are added, which linters complain about type. There is the added _late_import() method. You risk it is not run everywhere as needed. This has less overhead than an inline import, but there is still a check.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mo-imports-3.149.20327.tar.gz (5.4 kB view details)

Uploaded Source

File details

Details for the file mo-imports-3.149.20327.tar.gz.

File metadata

  • Download URL: mo-imports-3.149.20327.tar.gz
  • Upload date:
  • Size: 5.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/47.1.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.7.8

File hashes

Hashes for mo-imports-3.149.20327.tar.gz
Algorithm Hash digest
SHA256 32e3dc720c84765224d29ed7e9d6972a369d41d756e6f26ddb5b7aa01241331d
MD5 145b6283369c2267c049bec25448f06a
BLAKE2b-256 e28a52ec0e84bc8837d19da57ea9c1644c75b513d4f7aab7b3e24a437a4a047b

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page