Skip to main content

Static variables for Python

Project description

Static variables for Python

NOTE:

This is still very much a work in progress, and will segfault if you give it anything that is mildly complex. It will probably not work on any implementation except CPython.

Usage

static

from static_variables import static, resolve_static

# You don't really need to import `static`, it just stops
# IDEs from complaining.

@resolve_static
def f(to_add=None):
     ls = static([])
     if to_add is not None:
         ls.append(to_add)
     return ls

ls = f()
f(3)
assert ls == [3]  # True
assert ls is f()

Since Python variables are more like name tags, static will only really work well for mutable objects, like lists or io.StringIOs.

For example, the following does not work:

@resolve_static
def f():
    counter = static(0)
    counter += 1
    return counter

assert f() == 1  # True
assert f() == 2  # False

The only way to do that would be to reimplement a CPython byte-code interpreter in Python, and modify it to work.

The static variable will always have the same id. It will refer to the same object, and is stored at the end of a function’s function.__code__.co_consts

Empty set literals

Since sets came after dictionaries, the {} literal is an empty dictionary. This changes that.

@resolve_static(empty_set_literal=True)
def f():
    return {}

assert f() == set()  # True
assert f() != {}  # True; {} is dict() in the outer scope.

You can also use EMPTY_SET to avoid turning all {} into empty sets.

from static_variables import resolve_static, EMPTY_SET

# Again, you don't need to import EMPTY_SET.
# It just stops IDEs from complaining.

@resolve_static(empty_set_literal=False)
def f():
    my_dict = {}
    my_set = EMPTY_SET  # Equivalent to `set()` but faster.
    return type(my_dict), type(my_set)

assert f() == (dict, set)  # True

Speed?

It would actually be faster to use static, as it delegates some processing to declaration time, instead of run time.

Take these two snippets:

def product_4(it):
    return itertools.product(it, repeat=4)

@resolve_static
def static_product_4(it):
    return static(itertools.product)(it, repeat=4)

And their disassembly:

product_4(it)
              0 LOAD_GLOBAL              0 (itertools)
              2 LOAD_ATTR                1 (product)
              4 LOAD_FAST                0 (it)
              6 LOAD_CONST               1 (4)
              8 LOAD_CONST               2 (('repeat',))
             10 CALL_FUNCTION_KW         2
             12 RETURN_VALUE
static_product_4(it)
              0 LOAD_CONST               3 (<class 'itertools.product'>)
              2 LOAD_FAST                0 (it)
              4 LOAD_CONST               1 (4)
              6 LOAD_CONST               2 (('repeat',))
              8 CALL_FUNCTION_KW         2
             10 RETURN_VALUE

The static version just loads the itertools.product constant, whilst the normal version looks up a global variable and an attribute on one.

Empty set literals and EMPTY_SET are equivalent and both faster than set().

They are not equivalent to static(set()) which would be faster, but it would be the same static set.

Installation

From PyPI

$ pip install static_variables

From source

$ git clone 'https://github.com/MitalAshok/static_variables.git'
$ python ./static_variables/setup.py install

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

static_variables-0.0.2.tar.gz (10.1 kB view hashes)

Uploaded Source

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