hbutils.random.state
Random state and seed management utilities.
This module provides a centralized way to manage and synchronize random number
generator (RNG) states across multiple libraries. It supports the native Python
random module by default and can automatically register RNGs from optional
dependencies such as NumPy, PyTorch, and Faker when they are available. Custom
random sources or random.Random instances can also be registered manually.
The module exposes the following public components:
register_random_source()- Register an arbitrary RNG interfaceregister_random_instance()- Register arandom.Randominstanceget_global_state()- Collect current states from all registered RNGsset_global_state()- Restore RNG states from a mappingkeep_global_state()- Context manager that preserves RNG stateglobal_seed()- Apply a seed to all registered RNGsseedable_func()- Decorator for seed-aware functions
Note
Optional RNGs are only registered if the corresponding libraries are available in the current environment. If a library is missing, it is skipped silently.
Example:
>>> import random
>>> from hbutils.random import global_seed, get_global_state, set_global_state
>>>
>>> global_seed(0)
>>> random.random()
0.8444218515250481
>>> state = get_global_state()
>>> _ = random.random()
>>> set_global_state(state)
>>> random.random()
0.8444218515250481
T
- hbutils.random.state.T = ~T
Type variable.
Usage:
T = TypeVar('T') # Can be anything A = TypeVar('A', str, bytes) # Must be str or bytes
Type variables exist primarily for the benefit of static type checkers. They serve as the parameters for generic types as well as for generic function definitions. See class Generic for more information on generic types. Generic functions work as follows:
- def repeat(x: T, n: int) -> List[T]:
‘’’Return a list containing n references to x.’’’ return [x]*n
- def longest(x: A, y: A) -> A:
‘’’Return the longest of two strings.’’’ return x if len(x) >= len(y) else y
The latter example’s signature is essentially the overloading of (str, str) -> str and (bytes, bytes) -> bytes. Also note that if the arguments are instances of some subclass of str, the return type is still plain str.
At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError.
Type variables defined with covariant=True or contravariant=True can be used to declare covariant or contravariant generic types. See PEP 484 for more details. By default generic types are invariant in all type variables.
Type variables can be introspected. e.g.:
T.__name__ == ‘T’ T.__constraints__ == () T.__covariant__ == False T.__contravariant__ = False A.__constraints__ == (str, bytes)
Note that only type variables defined in global scope can be pickled.
__all__
- hbutils.random.state.__all__ = ['register_random_source', 'register_random_instance', 'get_global_state', 'set_global_state', 'keep_global_state', 'global_seed', 'seedable_func']
Built-in mutable sequence.
If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.
register_random_source
- hbutils.random.state.register_random_source(name: str, seed: Callable[[int], None], getstate: Callable[[], T], setstate: Callable[[T], None]) None[source]
Register a random source by providing its seed and state interfaces.
Each random source is identified by a unique name and must provide callable interfaces compatible with
seed(x),getstate(), andsetstate(state).- Parameters:
name (str) – Name of the random source.
seed (_SEED_FUNC) – Seed function with signature
seed(x).getstate (_GETSTATE_FUNC) – State retrieval function with signature
getstate().setstate (_SETSTATE_FUNC) – State restoration function with signature
setstate(state).
- Raises:
NameError – If the name already exists in registered random sources.
- Examples::
>>> import random >>> from hbutils.random import global_seed, register_random_source >>> >>> rnd = random.Random() # custom random object >>> global_seed(0) # try to use same seed >>> rnd.random() 0.4563765178328746 >>> global_seed(0) >>> rnd.random() # not same 0.06875325446897462 >>> >>> register_random_source('custom_random', rnd.seed, rnd.getstate, rnd.setstate) >>> global_seed(0) # try again >>> rnd.random() 0.8444218515250481 >>> global_seed(0) >>> rnd.random() # the same 0.8444218515250481
register_random_instance
- hbutils.random.state.register_random_instance(name: str, rnd: Random) None[source]
Register a custom
random.Randominstance.This is a convenience wrapper around
register_random_source()for instances compatible with Python’srandom.Randominterface.- Parameters:
name (str) – Name of random source.
rnd (random.Random) – Custom random instance.
- Examples::
>>> import random >>> from hbutils.random import global_seed, register_random_instance >>> >>> rnd = random.Random() # custom random object >>> global_seed(0) # try to use same seed >>> rnd.random() 0.48936053503964005 >>> global_seed(0) >>> rnd.random() # not same 0.4113361070387721 >>> >>> register_random_instance('custom_random', rnd) >>> global_seed(0) # try again >>> rnd.random() 0.8444218515250481 >>> global_seed(0) >>> rnd.random() # the same 0.8444218515250481
get_global_state
- hbutils.random.state.get_global_state() Dict[str, T][source]
Get states of all registered random sources.
- Returns:
A dictionary mapping random source names to their current states.
- Return type:
Dict[str, T]
- Examples::
>>> import random >>> import numpy as np >>> import torch >>> from faker import Faker >>> >>> from hbutils.random import get_global_state, set_global_state >>> >>> _ = random.randint(0, 100) # just do something >>> _ = random.random() >>> _ = torch.randn(2, 3) >>> _ = np.random.randn(2, 3) >>> >>> states = get_global_state() >>> random.randint(0, 100) # first time's result 99 >>> random.random() 0.4656250864192085 >>> torch.randn(2, 3) tensor([[ 0.8886, -0.3602, 1.3071], [-0.0187, -0.5980, -0.5469]]) >>> np.random.randn(2, 3) array([[ 1.24249156, 0.71018699, -0.53496231], [ 0.78748336, -0.01407442, -0.6607438 ]]) >>> Faker().sentence(5) 'New pass crime most.' >>> >>> set_global_state(states) >>> random.randint(0, 100) # same as the first time 99 >>> random.random() 0.4656250864192085 >>> torch.randn(2, 3) tensor([[ 0.8886, -0.3602, 1.3071], [-0.0187, -0.5980, -0.5469]]) >>> np.random.randn(2, 3) array([[ 1.24249156, 0.71018699, -0.53496231], [ 0.78748336, -0.01407442, -0.6607438 ]]) >>> Faker().sentence(5) 'New pass crime most.'
set_global_state
- hbutils.random.state.set_global_state(states: Mapping[str, T]) None[source]
Set states of registered random sources.
- Parameters:
states (Mapping[str, T]) – A mapping of random source names to their states to be restored.
Note
If a state is provided for a non-existent random source, a warning will be issued. If a registered random source is not provided in the states, a warning will be issued.
- Examples::
See
get_global_state().
keep_global_state
- hbutils.random.state.keep_global_state() Generator[None, None, None][source]
Context manager to preserve all random states during execution.
This context manager saves the current state of all registered random sources, executes the code block, and then restores the saved states regardless of whether the code block completes successfully or raises an exception.
- Yields:
None
- Return type:
Generator[None, None, None]
- Examples::
>>> import torch >>> from hbutils.random import global_seed, keep_global_state >>> >>> global_seed(0) >>> torch.randn(2, 3) # before value 1 tensor([[ 1.5410, -0.2934, -2.1788], [ 0.5684, -1.0845, -1.3986]]) >>> torch.randn(2, 3) # after value 1 tensor([[ 0.4033, 0.8380, -0.7193], [-0.4033, -0.5966, 0.1820]]) >>> >>> global_seed(0) >>> torch.randn(2, 3) # before value 2, same as 1 tensor([[ 1.5410, -0.2934, -2.1788], [ 0.5684, -1.0845, -1.3986]]) >>> with keep_global_state(): # do anything you want here ... _ = torch.randn(100, 200, 2) ... _ = torch.randint(20, 30, (30, 40)) >>> torch.randn(2, 3) # after value 2, same as 1 tensor([[ 0.4033, 0.8380, -0.7193], [-0.4033, -0.5966, 0.1820]])
global_seed
- hbutils.random.state.global_seed(seed: int) None[source]
Set seed for all registered random sources.
This function applies the same seed value to all registered random sources, ensuring reproducible random number generation across different libraries.
- Parameters:
seed (int) – Random seed value to be applied to all random sources.
- Examples::
seedable_func
- hbutils.random.state.seedable_func(func: Callable[[...], R]) Callable[[...], R][source]
Decorator to add seed support to a function.
This decorator wraps a function to add an optional
seedkeyword argument. When provided, the seed is applied to all registered random sources before executing the function, enabling reproducible results.- Parameters:
func (Callable[..., R]) – Function to be decorated.
- Returns:
Wrapped function with an additional
seedkeyword argument.- Return type:
Callable[…, R]
- Examples::
>>> import torch >>> from hbutils.random import seedable_func >>> >>> @seedable_func ... def get_random_value(mean, std): ... return torch.randn((2, 3)) * std + mean >>> >>> get_random_value(2, 3) tensor([[-0.0844, 5.2530, 3.4248], [ 4.4923, 0.0492, 3.6731]]) >>> get_random_value(2, 3) # not the same tensor([[2.7600, 2.5135, 0.6484], [1.2459, 0.1020, 2.5905]]) >>> >>> get_random_value(2, 3, seed=0) tensor([[ 6.6230, 1.1197, -4.5364], [ 3.7053, -1.2536, -2.1958]]) >>> get_random_value(2, 3, seed=1) tensor([[3.9841, 2.8008, 2.1850], [3.8640, 0.6443, 1.5016]]) >>> get_random_value(2, 3, seed=0) # repeatable tensor([[ 6.6230, 1.1197, -4.5364], [ 3.7053, -1.2536, -2.1958]])