tempvars Usage Examples¶
In all of these examples, it is assumed that TempVars
has already been imported and that foo and bar have
been defined as:
from tempvars import TempVars
foo = 1
bar = 2
The removal of a pre-existing variable from the namespace for the
duration of a with TempVars
context is termed masking here.
Temporary variables created within the managed context that match
one or more of names, starts, and/or ends are
discarded (removed from the namespace) when exiting the context.
Note
The most common use case us anticipated to be via either starts or ends, where a common prefix or suffix, respectively (such as t_ or _t), is used to mark all temporary variables within the managed context. See “Masking Variables by Pattern,” below.
Contents
Recommended Standard Usage¶
This author’s standard approach for using TempVars
is via the starts argument as follows:
>>> with TempVars(starts=['t_']):
... t_foo = foo
... t_baz = foo + bar
... print(t_foo + t_baz)
4
>>> print('t_foo' in dir())
False
>>> print('t_baz' in dir())
False
As shown, any variable desired to be temporary can just be prefixed with
t_, and it will not survive beyond the scope of the relevant
TempVars
suite.
Masking Specific Variables¶
The most basic usage is to supply individual variable names in the names argument:
>>> with TempVars(names=['foo', 'bar']):
... print('foo' in dir())
... print('bar' in dir())
...
False
False
>>> print(foo + bar)
3
Note
names must always be a list of strings, even when only one variable name is passed.
If a variable name passed to names doesn’t exist in the namespace,
TempVars
silently ignores it when entering the with block. It does,
however, still discard any matching variables from the namespace upon exiting
the with block:
>>> with TempVars(names=['baz']):
... print('foo' in dir())
... print('bar' in dir())
... print(2 * (foo + bar))
... baz = 5
... print(baz)
...
True
True
6
5
>>> print(2 * (foo + bar))
6
>>> 'baz' in dir()
False
Masking Variables by Pattern¶
As noted above, variables can also be masked by pattern matching. Currently, only ‘starts with’ and ‘ends with’ matching styles are supported:
>>> with TempVars(starts=['fo'], ends=['ar']):
... print('foo' in dir())
... print('bar' in dir())
...
False
False
>>> print(foo + bar)
3
To avoid accidental masking of system variables, the starts argument cannot start with a double underscore:
>>> try:
... with TempVars(starts=['__foo']):
... pass
... except ValueError:
... print('Argument rejected')
...
Argument rejected
Similarly, ends cannot end with a double underscore:
>>> try:
... with TempVars(ends=['foo__']):
... pass
... except ValueError:
... print('Argument rejected')
...
Argument rejected
As well, neither starts nor ends can be a single underscore, since this also would mask Python system variables:
>>> try:
... with TempVars(starts=['_']):
... pass
... except ValueError:
... print('Argument rejected')
...
Argument rejected
As with names, starts and ends also discard at exit any matching variables created within the with block, whether they existed previously or not:
>>> with TempVars(starts=['t_'], ends=['_t']):
... t_foo = 6
... bar_t = 7
... print(t_foo * bar_t)
...
42
>>> 't_foo' in dir()
False
>>> 'bar_t' in dir()
False
Discarding Masked Variables¶
If desired, TempVars
can be instructed not to restore any variables
it masks from the original namespace, effectively discarding them
permanently:
>>> with TempVars(names=['foo', 'bar'], restore=False):
... pass
...
>>> 'foo' in dir()
False
>>> 'bar' in dir()
False
TempVars
contexts can be freely nested to allow selective
restore/discard behavior:
>>> with TempVars(names=['foo'], restore=False):
... with TempVars(names=['bar']):
... foo = 3
... bar = 5
... print(foo * bar)
... print(foo * bar)
15
6
>>> print(bar)
2
>>> 'foo' in dir()
False
Binding TempVars Instances¶
TempVars
is constructed so that each instance can be bound as part
of the with statement, for later inspection within and after the
managed context. The masking pattern arguments are stored without
modification, but are duplicated from the input argument to avoid munging of
mutable arguments:
>>> names_in = ['foo']
>>> with TempVars(names=names_in, starts=['baz', 'quux'], ends=['ar']) as tv:
... print(tv.starts)
... print(tv.ends)
... print(tv.names)
... print('foo' in dir())
... print('bar' in dir())
['baz', 'quux']
['ar']
['foo']
False
False
>>> names_in.append('quorz')
>>> print(tv.names)
['foo']
As shown above, these instance variables can also be examined after the end of the managed context.
Inspecting Masked Variables¶
TempVars
provides a means to access the masked variables from within
the managed context, via the stored_nsvars
instance variable:
>>> with TempVars(names=['foo']) as tv:
... print(list(tv.stored_nsvars.keys()))
... print(tv.stored_nsvars['foo'])
... print('foo' in dir())
['foo']
1
False
The masked variables remain available after the end of the managed context, even if they are not restored when the context exits:
>>> with TempVars(names=['foo']) as tv:
... pass
>>> print(tv.stored_nsvars['foo'])
1
>>> with TempVars(names=['bar'], restore=False) as tv2:
... pass
>>> print('bar' in dir())
False
>>> print(tv2.stored_nsvars['bar'])
2
A caveat: the masked variables are bound within
stored_nsvars
by simple assignment,
which can have (possibly undesired) side effects when
mutable objects are modified after being masked:
>>> baz = [1, 2, 3]
>>> with TempVars(names=['baz']) as tv:
... tv.stored_nsvars['baz'].append(12)
>>> print(baz)
[1, 2, 3, 12]
>>> baz.remove(2)
>>> print(tv.stored_nsvars['baz'])
[1, 3, 12]
If copy()
or deepcopy()
behavior is of interest,
please add a comment to that effect on the
related GitHub issue.
Inspecting Discarded Temporary Variables¶
In an analogous fashion to stored_nsvars
,
the temporary variables discarded from the namespace at the exit of
the managed context are stored in
retained_tempvars
:
>>> with TempVars(names=['foo']) as tv:
... foo = 5
... print(foo * bar)
10
>>> print(foo + tv.retained_tempvars['foo'])
6
Also as with stored_nsvars
, at this time
the values within retained_tempvars
are
bound by simple assignment, leading to similar possible side effects:
>>> baz = [1, 2]
>>> with TempVars(names=['baz']) as tv:
... tv.stored_nsvars['baz'].append(3)
... baz = tv.stored_nsvars['baz']
>>> tv.retained_tempvars['baz'].append(4)
>>> print(baz)
[1, 2, 3, 4]
As above, if copy()
and/or deepcopy()
behavior is of interest, please comment on the
relevant GitHub issue.