Skip to main content

Late allows for late binding of default arguments

Reason this release was yanked:

outdated

Project description

lincense version fury downloada tests

Late

Late binding for Python default arguments

What is it?

Late provides decorators and functions to work around the issues that early binding of default argument values produces in Python.

What follows is not intuitive for newcomers to Python, but it's something that everyone learns quickly:

>>> def f(x=[]):
...     x.append(1)
...     return x
...
>>> f()
[1]
>>> f()
[1, 1]
>>> f()
[1, 1, 1]

The behavior in Python is that the same initializer value is passed on every function invocation, so using mutable values produces the above results.

The coding pattern to work around the above is to use None as the initializer, and check for the parameter value at the start of the function code:

>>> def f(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     return x
...
>>> f()
[1]
>>> f()
[1]
>>> f()
[1]

It's ugly, but it works.

Now comes the other ugly part. When using type annotations, the above function must be declared in a way so that type checkers do not complain about using None as the default value:

>>> def f(x: list[Any] | None = None) -> list[Any]:

Late provides a way to solve the above ugliness with some decorator magic. This is how the code looks with some of that magic:

from late import latebinding, __


@latebinding
def f(x: list[Any] = __([])) -> list[Any]:
    x.append(1)
    return x

assert f() == [1]
assert f() == [1]
assert f() == [1]

Working with classes

Late also works with classes and dataclass. The @latebinding decorator must be the outer one:

@latebinding
@dataclass
class C:
    x: list[Any] = __([])  # noqa

c = C()
assert c.x == []

d = C()
assert d.x == []
c.x = [1]
assert c.x == [1]
assert d.x == []

assert d.x is not c.x

Working with generators

Late allows passing a generator as a default argument value, and it will provide the next value on each function call. The usefulness of this feature is unknown, but it's something that came up during the discussions about default arguments, so Late implements it.

    def fib() -> Iterator[int]:
        x, y = 0, 1
        while True:
            yield x
            x, y = y, x + y


    @latebinding
    def f(x: int = __(fib())) -> int:
        return x

    assert f() == 0
    assert f() == 1
    assert f() == 1
    assert f() == 2
    assert f() == 3
    assert f() == 5

This is a possible use for the generators feature. Imagine a function that requires a unique ID, and will generate one if none is provided. Without Late the declaration would be:

def get_session(uniqueid: int | None = None) -> Session:
    if uniqueid is None:
        uniqueid = make_unique_id()

Using Late, the declaration can be:

def unique_id_generator() -> Iterator[int]:
    while True:
        yield make_unique_id()
        
def get_session(uniqueid: int = __(unique_id_generator())) -> Session:

Working with functions

Late also allows lat-binding functions, so the above example could be implemented using a function instead of a generator:

def get_session(uniqueid: int = __(make_unique_id)) -> Session:

The given function will be called once every time the uniqueid parameter is omitted.

About name choice

The names of what Late exports are chosen to be explicit where it matters, and to not get in the way of the visuals of a declaration. In particular, __() was chosen to interfere the least possible with reading a function declaration (late() is another name for it, and __ is seldom used in Python code).

At any rate, Late is so simple and so small that you can apply any changes you like and use it as another part of your code instead of installing it as a library.

Installation

$ pip install Late

License

Late is licensed under the GNU LESSER GENERAL PUBLIC LICENSE Version 3, as reads in the LICENSE file.

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

Late-1.1.0.tar.gz (8.0 kB view details)

Uploaded Source

Built Distribution

Late-1.1.0-py3-none-any.whl (11.1 kB view details)

Uploaded Python 3

File details

Details for the file Late-1.1.0.tar.gz.

File metadata

  • Download URL: Late-1.1.0.tar.gz
  • Upload date:
  • Size: 8.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.12.0

File hashes

Hashes for Late-1.1.0.tar.gz
Algorithm Hash digest
SHA256 bee01acf95e054a296fa3c9fcf2d7a30d127daaf22aba6ba3ceaa28587dbac89
MD5 ca71568622d5f9e3741e8cba58805eb5
BLAKE2b-256 3769181c559d6db47f0afaff809da22f0e109d0170783af3f55a92c840d3b999

See more details on using hashes here.

File details

Details for the file Late-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: Late-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.12.0

File hashes

Hashes for Late-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bce1b5cb641f5b4d7acdd18e1e475140c401af1d60aec380bf054c3754611899
MD5 0beab66fef0b0b71f2dff67b199a37d2
BLAKE2b-256 753120f4ed1bc018f08503131f2c462a203d688463e4341d47a2e24c6563084d

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