ContextualValue#
- class penzai.core.context.ContextualValue[source]#
Bases:
Generic
[T
]A global value which can be modified in a scoped context.
Mutable global values can be difficult to reason about, but can also be very convenient for reducing boilerplate and focusing on the important parts if they are used carefully. Moreover, it’s common to only want to change a global value within a particular delimited scope, without affecting anything beyond that scope.
This class manages a restricted form of global value access to support this use case: read access is allowed anywhere, but updates are only “local”, in the sense that they apply for the duration of a delimited scope and don’t affect anything beyond that scope. (This is similar to a Reader monad in functional programming languages.)
If you have many values to set, or you want to set them conditionally, consider using a
contextlib.ExitStack
, e.g.with contextlib.ExitStack() as stack: stack.enter_context(contextual_one.set_scoped(True)) if foo: stack.enter_context(contextual_two.set_scoped(some_value)) # logic that uses those values # all contexts are exited here
or just
stack = contextlib.ExitStack() stack.enter_context(contextual_one.set_scoped(True)) if foo: stack.enter_context(contextual_two.set_scoped(some_value)) # ... do something ... # ... then eventually: stack.close()
If you would like to modify contextual values at the global level (e.g. for interactive use), you can call
enable_interactive_context
in this module and then useset_interactive
instead ofset_scoped
; this is actually implemented using an internally-managed globalExitStack
.- Variables:
__module__ (str | None) – The module where this contextual value is defined.
__qualname__ (str | None) – The fully-qualified name of the contextual value within its module.
_raw_value (T) – The current value. Should not be used directly; use
get
to get it orset_scoped
to set it within a context.
Methods
__init__
(initial_value[, module, qualname])Creates a contextual value.
get
()Retrieves the current value.
set_interactive
(new_value)Sets the value in interactive mode.
set_scoped
(new_value)Returns a context manager in which the value will be modified.
- __init__(initial_value: T, module: str | None = None, qualname: str | None = None)[source]#
Creates a contextual value.
- Parameters:
initial_value – A value to use outside of
set_scoped
contexts.module – The module where this contextual value is defined. Usually this will be
__name__
(for whichever model it was defined in).qualname – The fully-qualified name of the contextual value within its module.
- set_interactive(new_value: T) None [source]#
Sets the value in interactive mode.
This function should ONLY be called in an interactive setting (e.g. a Colab notebook or repl), and must be called after
enable_interactive_context
but beforedisable_interactive_context
.disable_interactive_context
will restore all contexts set usingset_interactive
to their original states.- Parameters:
new_value – The new value to use in this context.
- Raises:
RuntimeError – If interactive contexts have not been enabled.
- set_scoped(new_value: T)[source]#
Returns a context manager in which the value will be modified.
This allows scoped modifications to the value, using something like
contextual = ContextualValue(10) with contextual.set_scoped(3): v1 = contextual.get() # v1 is 3 v2 = contextual.get() # v2 is 10
If you want to conditionally set the value, consider using
contextlib.ExitStack
:with contextlib.ExitStack() as exit_stack: if condition: exit_stack.enter_context(contextual.set_scoped(3)) # use contextual.get() here
- Parameters:
new_value – The new value to use in this context.
- Returns:
A context manager in which
new_value
is set.