Query Scope
Deephaven query strings allow complex queries to be expressed with a concise syntax. These query strings can implement formulas that use Python variables. For example, the query string in this update
uses the variable a
from Python.
a = 2
t2 = t.update(["Y = a * X"])
When the Deephaven engine compiles a query string, it must be able to resolve all variables in the query string. This is done using the query scope. The Deephaven query scope follows rules similar to Python's LEGB rule, with some important distinctions.
Query strings in Deephaven Python queries resolve variables with the following precedence:
- Local (function) scope
- Global (module) scope
The enclosing (nonlocal) scope is not directly supported. If you want to use a variable in the enclosing scope in a query string, you must use the nonlocal
keyword to do so.
Examples
Variable and function names are case-sensitive.
Local (function) scope
Variables defined in the local scope of a function or lambda expression are usable only from within that function or lambda. The following query uses the local scope to create a table, which is visible in the outermost scope. The function uses both a local and global variable to create the table.
from deephaven import empty_table
global_var = 99
def use_local_and_global_vars(num_rows):
local_var = 23
return empty_table(num_rows).update(["X = global_var * i", "Y = local_var * i"])
result = use_local_and_global_vars(10)
- result
Global (module) scope
Variables defined at the outermost scope are usable from within any query string in a query. The following query creates two variables in the outermost scope, then creates a table with those values.
from deephaven import empty_table
a = 1
b = 2
result1 = empty_table(1).update(["A = a", "B = b"])
result2 = empty_table(5).update(["A = i * a", "B = i * b"])
- result1
- result2
Enclosing (nonlocal) scope
Variables that exist in the enclosing scope are usable from only within the enclosing scope. If you wish to use an object in the enclosing scope in a query string, you must use the nonlocal
keyword before using it. The following query uses a variable in the enclosing scope to update a table.
from deephaven import empty_table
def outer_func():
enclosing_var = 2
def inner_func():
nonlocal enclosing_var
local_var = 7
return empty_table(5).update(["X = i * local_var", "Y = i * enclosing_var"])
return inner_func()
result = outer_func()
- result
User-defined functions in a query string
Programming languages frequently implement functions as callable objects. Python is no different.
In the following example, my_function
is defined in the global scope and is called from the query string twice. In the first call, my_function
is explicitly cast to an integer because of the additional arithmetic in the query string itself. In the second call, the output of my_function
does not need to be typecast because of the type hint in the function itself.
from deephaven import new_table
from deephaven.column import int_col
import numpy as np
def my_function(a) -> np.intc:
return a * (a + 1)
source = new_table([int_col("A", [1, 2, 3])])
result = source.update(
formulas=["X = 2 + 3 * (int)my_function(A)", "Y = my_function(X)"]
)
- source
- result
Encapsulated query logic in functions
One can encapsulate query logic within functions. Such functions may use variables in query strings.
In the following example, the compute
function performs a query using the source
table and the input parameter a
. Here, a
is defined in the local scope of compute
, and therefore can only be used from within the function itself.
from deephaven import new_table
from deephaven.column import int_col
import numpy as np
def f(a, b) -> np.intc:
return a * b
def compute(source, a):
return source.update(formulas=["X = f(a, A)"])
source = new_table([int_col("A", [1, 2, 3])])
result1 = compute(source, 10)
result2 = compute(source, 3)
- source
- result1
- result2