Skip to main content

Python Singleton Metaclasses

Description

A package of python metclasses for implementing singleton and related patterns.

Singleton Class

This implements the traditional singleton pattern. Once an instance of a class is created, all future instantiations result in the same object.

Memoized Class

This applies the notion of "memoization" to object creation. Multiple calls to a constructor with the same first parameter result in the same object.

Calls to the constructor with a new first parameter result in a new object instance.

This is useful in situations where a singleton is called for if the arguments are the same, but a new instance is called for when new arguments are provided.

For example, if an object parses a file, there may be no need to parse the same file more than once. So all instantiations of the parser on the same file result in the same object instance. But for a new file that has yet to be parsed, a new instance will be created.

Alowing Object Cleanup

One drawback is the singleton (and memoized) object does not get freed. If it is desired for the singleton objects to be destroyed no longer required, there are a couple of options:

  • In the class definition, declare a class variable, _PYSINGLETON_WEAKREF = True (or _PYMEMOIZED_WEAKREF as appropriate)
  • Create an environment variable constructed from the class name and set it to '1':
    • export MySingleton_WEAKREF=1

This causes instances to be tracked by the metaclass using weak references. The garbage collector will destroy them when the last normal reference has gone out of scope. The next time the class is instantiated, a new instance will be created.

Examples


Singleton Class Example

from pysingleton import PySingleton  # noqa: E402


class MySingleton(metaclass=PySingleton):
    def __init__(self, value):
        self.value = value


# Create first instance and inspect value
my_singleton_1 = MySingleton(1)
print("my_singleton_1.value: {}".format(my_singleton_1.value))

# Create second instance with new constructor param
my_singleton_2 = MySingleton(2)
# Inspect value and see it matches the original
print("my_singleton_2.value: {}".format(my_singleton_2.value))

# First and second instances' values are equal
print("my_singleton_1.value == my_singleton_2.value: {}".format(
    my_singleton_1.value == my_singleton_2.value))

# change second instance's value
my_singleton_2.value = 7

# Inspect first instance's value and see it has changed
print("my_singleton_1.value: {}".format(my_singleton_1.value))

# First and second instance have the same object ID:
print("id(my_singleton_1): {:#x}".format(id(my_singleton_1)))
print("id(my_singleton_2): {:#x}".format(id(my_singleton_2)))
$ python ./example.py
my_singleton_1.value: 1
my_singleton_2.value: 1
my_singleton_1.value == my_singleton_2.value: True
my_singleton_1.value: 7
id(my_singleton_1): 0x101c29b80
id(my_singleton_2): 0x101c29b80

Memoized Class Example

from pysingleton import PyMemoized  # noqa: E402


class MyMemoized(metaclass=PyMemoized):
    def __init__(self, param1, param2):
        self.value = param2


# Create first instance and inspect value
my_memoized_1 = MyMemoized("arg1", 1)
print("my_memoized_1.value: {}".format(my_memoized_1.value))

# Create second instance with the original param1 but new param2
my_memoized_2 = MyMemoized("arg1", 2)
# Inspect value and see it matches the original
print("my_memoized_2.value: {}".format(my_memoized_2.value))

# First and second instances' values are equal
print("my_memoized_1.value == my_memoized_2.value: {}".format(
    my_memoized_1.value == my_memoized_2.value))

# change second instance's value
my_memoized_2.value = 7

# Inspect first instance's value and see it has changed
print("my_memoized_1.value: {}".format(my_memoized_1.value))

# Create third instance with new param1 & param2, and see
# it takes the new value
my_memoized_3 = MyMemoized("arg3", 3)
print("my_memoized_3.value: {}".format(my_memoized_3.value))

# First and third  instances' values are not equal
print("my_memoized_1.value == my_memoized_3.value: {}".format(
    my_memoized_1.value == my_memoized_3.value))


# First and second instance have the same object ID
print("id(my_memoized_1): {:#x}".format(id(my_memoized_1)))
print("id(my_memoized_2): {:#x}".format(id(my_memoized_2)))

# but third instance's object ID is different
print("id(my_memoized_3): {:#x}".format(id(my_memoized_3)))
python3 ./examples/memoized-example.py
my_memoized_1.value: 1
my_memoized_2.value: 1
my_memoized_1.value == my_memoized_2.value: True
my_memoized_1.value: 7
my_memoized_3.value: 3
my_memoized_1.value == my_memoized_3.value: False
id(my_memoized_1): 0x100773b80
id(my_memoized_2): 0x100773b80
id(my_memoized_3): 0x100818340

Metadata

Release files for python-singleton-metaclasses 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-singleton-metaclasses 0.2.1
File Size Uploaded Provenance Actions
python-singleton-metaclasses-0.2.1.tar.gz 4.3 kB Without provenance Details for python-singleton-metaclasses-0.2.1.tar.gz

Release files / python-singleton-metaclasses-0.2.1.tar.gz

Download URL python-singleton-metaclasses-0.2.1.tar.gz
Size 4.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7abaad530dd1e2aa74bd0a8a00fd6bf9acf811e015f1eb68024147a4f202be1e
BLAKE2b-256 checksum
How to use checksums
bb1fb384478a70e18d6464283588263a9ad4d31fa9cf05334aa821edd1faf38a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.1 CPython/3.10.8

Security for python-singleton-metaclasses 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page