Note
This document describes an advanced feature designed to overcome some limitations of the compilation mechanism relating to types.
Some features need to specialize based on the literal value during
compliation to produce type stable code necessary for successful compilation in
Numba. This can be achieved by propagating the literal value through the type
system. Numba recognizes inline literal values as numba.types.Literal
.
For example:
def foo(x):
a = 123
return bar(x, a)
Numba will infer the type of a
as Literal[int](123)
. The definition of
bar()
can subsequently specialize its implementation knowing that the
second argument is an int
with the value 123
.
Literal
Type¶Classes and methods related to the Literal
type.
numba.types.
Literal
(value)¶Base class for Literal types. Literal types contain the original Python value in the type.
A literal type should always be constructed from the literal(val) function.
numba.types.
literal
(value)¶Returns a Literal instance or raise LiteralTypingError
numba.types.
unliteral
(lit_type)¶Get base type from Literal type.
numba.types.
maybe_literal
(value)¶Get a Literal type for the value or None.
To specify a value as a Literal
type in code scheduled for JIT compilation,
use the following function:
numba.
literally
(obj)¶Forces Numba to interpret obj as an Literal value.
obj must be either a literal or an argument of the caller function, where the argument must be bound to a literal. The literal requirement propagates up the call stack.
This function is intercepted by the compiler to alter the compilation
behavior to wrap the corresponding function parameters as Literal
.
It has no effect outside of nopython-mode (interpreter, and objectmode).
The current implementation detects literal arguments in two ways:
literally
via a compiler pass.literally
is overloaded to raise numba.errors.ForceLiteralArg
to signal the dispatcher to treat the corresponding parameter
differently. This mode is to support indirect use (via a function call).The execution semantic of this function is equivalent to an identity function.
See numba/tests/test_literal_dispatch.py for examples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import numba
def power(x, n):
raise NotImplementedError
@numba.extending.overload(power)
def ov_power(x, n):
if isinstance(n, numba.types.Literal):
# only if `n` is a literal
if n.literal_value == 2:
# special case: square
print("square")
return lambda x, n: x * x
elif n.literal_value == 3:
# special case: cubic
print("cubic")
return lambda x, n: x * x * x
print("generic")
return lambda x, n: x ** n
@numba.njit
def test_power(x, n):
return power(x, numba.literally(n))
# should print "square" and "9"
print(test_power(3, 2))
# should print "cubic" and "27"
print(test_power(3, 3))
# should print "generic" and "81"
print(test_power(3, 4))
|
Internally, the compiler raises a ForceLiteralArgs
exception to signal
the dispatcher to wrap specified arguments using the Literal
type.
numba.errors.
ForceLiteralArg
(arg_indices, fold_arguments=None, loc=None)¶A Pseudo-exception to signal the dispatcher to type an argument literally
Attributes: |
|
---|
__init__
(self, arg_indices, fold_arguments=None, loc=None)¶Parameters: |
|
---|
__or__
(self, other)¶Same as self.combine(other)
combine
(self, other)¶Returns a new instance by or’ing the requested_args.
@overload
extensions can use literally
inside the implementation body
like in normal jit-code.
Explicit handling of literal requirements is possible through use of the following:
numba.extending.
SentryLiteralArgs
¶Parameters: |
|
---|
Examples
The following line:
>>> SentryLiteralArgs(literal_args).for_pysig(pysig).bind(*args, **kwargs)
is equivalent to:
>>> sentry_literal_args(pysig, literal_args, args, kwargs)
for_function
(self, func)¶Bind the sentry to the signature of func.
Parameters: |
|
---|---|
Returns: |
|
for_pysig
(self, pysig)¶Bind the sentry to the given signature pysig.
Parameters: |
|
---|---|
Returns: |
|
numba.extending.
BoundLiteralArgs
¶This class is usually created by SentryLiteralArgs.
bind
(self, *args, **kwargs)¶Bind to argument types.
numba.extending.
sentry_literal_args
(pysig, literal_args, args, kwargs)¶Ensures that the given argument types (in args and kwargs) are literally typed for a function with the python signature pysig and the list of literal argument names in literal_args.
Alternatively, this is the same as:
SentryLiteralArgs(literal_args).for_pysig(pysig).bind(*args, **kwargs)