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_WEAKREFas 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)
| 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.