types¶
Module with general purpose types.
-
nutils.types.
aspreprocessor
(apply)¶ Convert
apply
into a preprocessor decorator. When applied to a function,wrapped
, the returned decorator preprocesses the arguments withapply
before callingwrapped
. Theapply
function should return a tuple ofargs
(tuple
orlist
) andkwargs
(dict
). The decorated functionwrapped
will be called withwrapped(*args, **kwargs)
. Theapply
function is allowed to change the signature of the decorated function.Examples
The following preprocessor swaps two arguments.
>>> @aspreprocessor ... def swapargs(a, b): ... return (b, a), {}
Decorating a function with
swapargs
will cause the arguments to be swapped before the wrapped function is called.>>> @swapargs ... def func(a, b): ... return a, b >>> func(1, 2) (2, 1)
-
nutils.types.
apply_annotations
(wrapped)¶ Decorator that applies annotations to arguments. All annotations should be
callable
s taking one argument and returning a transformed argument. All annotations are strongly recommended to be idempotent.If a parameter of the decorated function has a default value
None
and the value of this parameter isNone
as well, the annotation is omitted.Examples
Consider the following function.
>>> @apply_annotations ... def f(a:tuple, b:int): ... return a + (b,)
When calling
f
with alist
andstr
as arguments, theapply_annotations()
decorator first appliestuple
andint
to the arguments before passing them to the decorated function.>>> f([1, 2], '3') (1, 2, 3)
The following example illustrates the behavior of parameters with default value
None
.>>> addone = lambda x: x+1 >>> @apply_annotations ... def g(a:addone=None): ... return a
When calling
g
without arguments or with argumentNone
, the annotationaddone
is not applied. Note thatNone + 1
would raise an exception.>>> g() is None True >>> g(None) is None True
When passing a different value, the annotation is applied:
>>> g(1) 2
-
nutils.types.
argument_canonicalizer
(signature)¶ Returns a function that converts arguments matching
signature
to canonical positional and keyword arguments. If possible, an argument is added to the list of positional arguments, otherwise to the keyword arguments dictionary. The returned arguments include default values.- Parameters
signature (
inspect.Signature
) – The signature of a function to generate canonical arguments for.- Returns
A function that returns a
tuple
of atuple
of positional arguments and adict
of keyword arguments.- Return type
Examples
Consider the following function.
>>> def f(a, b=4, *, c): pass
The
argument_canonicalizer
forf
is generated as follows:>>> canon = argument_canonicalizer(inspect.signature(f))
Calling
canon
with parameterb
passed as keyword returns arguments with parameterb
as positional argument:>>> canon(1, c=3, b=2) ((1, 2), {'c': 3})
When calling
canon
without parameterb
the default value is added to the positional arguments:>>> canon(1, c=3) ((1, 4), {'c': 3})
-
nutils.types.
nutils_hash
(data)¶ Compute a stable hash of immutable object
data
. The hash is not affected by Python’s hash randomization (seeobject.__hash__()
).
-
class
nutils.types.
CacheMeta
(name, bases, namespace, **kwargs)¶ Bases:
abc.ABCMeta
Metaclass that adds caching functionality to properties and methods listed in the special attribute
__cache__
. If an attribute is of typeproperty
, the value of the property will be computed at the first attribute access and served from cache subsequently. If an attribute is a method, the arguments and return value are cached and the cached value will be used if a subsequent call is made with the same arguments; if not, the cache will be overwritten. The cache lives in private attributes in the instance. The metaclass supports the use of__slots__
. If a subclass redefines a cached property or method (in the sense of this metaclass) of a base class, the property or method of the subclass is not automatically cached;__cache__
should be used in the subclass explicitly.Examples
An example of a class with a cached property:
>>> class T(metaclass=CacheMeta): ... __cache__ = 'x', ... @property ... def x(self): ... print('uncached') ... return 1
The print statement is added to illustrate when method
x
(as defined above) is called:>>> t = T() >>> t.x uncached 1 >>> t.x 1
An example of a class with a cached method:
>>> class U(metaclass=CacheMeta): ... __cache__ = 'y', ... def y(self, a): ... print('uncached') ... return a
Again, the print statement is added to illustrate when the method
y
(as defined above) is called:>>> u = U() >>> u.y(1) uncached 1 >>> u.y(1) 1 >>> u.y(2) uncached 2 >>> u.y(2) 2
-
class
nutils.types.
Immutable
(*args, **kwargs)¶ Bases:
object
Base class for immutable types. This class adds equality tests, traditional hashing (
hash()
), nutils hashing (nutils_hash()
) and pickling, all based solely on the (positional) intialization arguments,args
for future reference. Keyword-only arguments are not supported. All arguments should be hashable bynutils_hash()
.Positional and keyword initialization arguments are canonicalized automatically (by
argument_canonicalizer()
). If the__init__
method of a subclass is decorated with preprocessors (seeaspreprocessor()
), the preprocessors are applied to the initialization arguments andargs
becomes the preprocessed positional part.Examples
Consider the following class.
>>> class Plain(Immutable): ... def __init__(self, a, b): ... pass
Calling
Plain
with equivalent positional or keyword arguments produces equal instances:>>> Plain(1, 2) == Plain(a=1, b=2) True
Passing unhashable values to
Plain
will fail:>>> Plain([1, 2], [3, 4]) Traceback (most recent call last): ... TypeError: unhashable type: 'list'
This can be solved by adding and applying annotations to
__init__
. The following class converts its initialization arguments totuple
automaticaly:>>> class Annotated(Immutable): ... @apply_annotations ... def __init__(self, a:tuple, b:tuple): ... pass
Calling
Annotated
with eitherlist
s of1, 2
and3, 4
ortuple
s gives equal instances:>>> Annotated([1, 2], [3, 4]) == Annotated((1, 2), (3, 4)) True
-
class
nutils.types.
Singleton
(*args, **kwargs)¶ Bases:
nutils.types.Immutable
Subclass of
Immutable
that creates a single instance per unique set of initialization arguments.Examples
Consider the following class.
>>> class Plain(Singleton): ... def __init__(self, a, b): ... pass
Calling
Plain
with equivalent positional or keyword arguments produces one instance:>>> Plain(1, 2) is Plain(a=1, b=2) True
Consider the folling class with annotations.
>>> class Annotated(Singleton): ... @apply_annotations ... def __init__(self, a:tuple, b:tuple): ... pass
Calling
Annotated
with eitherlist
s of1, 2
and3, 4
ortuple
s gives a single instance:>>> Annotated([1, 2], [3, 4]) is Annotated((1, 2), (3, 4)) True
-
__eq__
(self, value, /)¶ Return self==value.
-
-
nutils.types.
strictint
(value)¶ Converts any type that is a subclass of
numbers.Integral
(e.g.int
andnumpy.int64
) toint
, and fails otherwise. Notable differences with the behavior ofint
:strictint()
does not convert astr
to anint
.strictint()
does not truncatefloat
to anint
.
Examples
>>> strictint(1), type(strictint(1)) (1, <class 'int'>) >>> strictint(numpy.int64(1)), type(strictint(numpy.int64(1))) (1, <class 'int'>) >>> strictint(1.0) Traceback (most recent call last): ... ValueError: not an integer: 1.0 >>> strictint('1') Traceback (most recent call last): ... ValueError: not an integer: '1'
-
nutils.types.
strictfloat
(value)¶ Converts any type that is a subclass of
numbers.Real
(e.g.float
andnumpy.float64
) tofloat
, and fails otherwise. Notable difference with the behavior offloat
:strictfloat()
does not convert astr
to anfloat
.
Examples
>>> strictfloat(1), type(strictfloat(1)) (1.0, <class 'float'>) >>> strictfloat(numpy.float64(1.2)), type(strictfloat(numpy.float64(1.2))) (1.2, <class 'float'>) >>> strictfloat(1.2+3.4j) Traceback (most recent call last): ... ValueError: not a real number: (1.2+3.4j) >>> strictfloat('1.2') Traceback (most recent call last): ... ValueError: not a real number: '1.2'
-
nutils.types.
strictstr
(value)¶ Returns
value
unmodified if it is astr
, and fails otherwise. Notable difference with the behavior ofstr
:strictstr()
does not call__str__
methods of objects to automatically convert objects tostr
s.
Examples
Passing a
str
tostrictstr()
works:>>> strictstr('spam') 'spam'
Passing an
int
will fail:>>> strictstr(1) Traceback (most recent call last): ... ValueError: not a 'str': 1
-
class
nutils.types.
strict
(*args, **kwargs)¶ Bases:
object
Type checker. The function
strict[cls](value)
returnsvalue
unmodified ifvalue
is an instance ofcls
, otherwise aValueError
is raised.Examples
The
strict[int]
function passes integers unmodified:>>> strict[int](1) 1
Other types fail:
>>> strict[int]('1') Traceback (most recent call last): ... ValueError: expected an object of type 'int' but got '1' with type 'str'
-
__weakref__
¶ list of weak references to the object (if defined)
-
-
class
nutils.types.
tuple
(*args, **kwargs)¶ Bases:
tuple
Wrapper of
tuple
that supports a user-defined item constructor via the notationtuple[I]
, withI
the item constructor. This is shorthand forlambda items: tuple(map(I, items))
. The item constructor should be any callable that takes one argument.Examples
A tuple with items processed with
strictint()
:>>> tuple[strictint]((False, 1, 2, numpy.int64(3))) (0, 1, 2, 3)
If the item constructor raises an exception, the construction of the
tuple
failes accordingly:>>> tuple[strictint]((1, 2, 3.4)) Traceback (most recent call last): ... ValueError: not an integer: 3.4
-
class
nutils.types.
frozendict
(base)¶ Bases:
collections.abc.Mapping
An immutable version of
dict
. Thefrozendict
is hashable and both the keys and values should be hashable as well.Custom key and value constructors can be supplied via the
frozendict[K,V]
notation, withK
the key constructor andV
the value constructor, which is roughly equivalent tolambda *args, **kwargs: {K(k): V(v) for k, v in dict(*args, **kwargs).items()}
.Examples
A
frozendict
withstrictstr()
as key constructor andstrictfloat()
as value constructor:>>> frozendict[strictstr,strictfloat]({'spam': False}) frozendict({'spam': 0.0})
Similar but with non-strict constructors:
>>> frozendict[str,float]({None: '1.2'}) frozendict({'None': 1.2})
Applying the strict constructors to invalid data raises an exception:
>>> frozendict[strictstr,strictfloat]({None: '1.2'}) Traceback (most recent call last): ... ValueError: not a 'str': None
-
class
nutils.types.
frozenmultiset
(items)¶ Bases:
collections.abc.Container
An immutable multiset. A multiset is a generalization of a set: items may occur more than once. Two mutlisets are equal if they have the same set of items and the same item multiplicities.
A custom item constructor can be supplied via the notation
frozenmultiset[I]
, withI
the item constructor. This is shorthand forlambda items: frozenmultiset(map(I, items))
. The item constructor should be any callable that takes one argument.Examples
>>> a = frozenmultiset(['spam', 'bacon', 'spam']) >>> b = frozenmultiset(['sausage', 'spam'])
The
frozenmultiset
objects support+
,-
and&
operators:>>> a + b frozenmultiset(['spam', 'bacon', 'spam', 'sausage', 'spam']) >>> a - b frozenmultiset(['bacon', 'spam']) >>> a & b frozenmultiset(['spam'])
The order of the items is irrelevant:
>>> frozenmultiset(['spam', 'spam', 'eggs']) == frozenmultiset(['spam', 'eggs', 'spam']) True
The multiplicities, however, are not:
>>> frozenmultiset(['spam', 'spam', 'eggs']) == frozenmultiset(['spam', 'eggs']) False
-
__and__
(self, other)¶ Return a
frozenmultiset
with elements from the left and right hand sides with strict positive multiplicity, where the multiplicity is the minimum of multiplicitie of the left and right hand side.
-
__add__
(self, other)¶ Return a
frozenmultiset
with elements from the left and right hand sides with a multiplicity equal to the sum of the left and right hand sides.
-
__sub__
(self, other)¶ Return a
frozenmultiset
with elements from the left hand sides with a multiplicity equal to the difference of the multiplicity of the left and right hand sides, truncated to zero. Elements with multiplicity zero are omitted.
-
-
class
nutils.types.
frozenarray
(base, dtype=None, copy=True)¶ Bases:
collections.abc.Sequence
An immutable version (and drop-in replacement) of
numpy.ndarray
.Besides being immutable, the
frozenarray
differs fromnumpy.ndarray
in (in)equality tests. Given twofrozenarray
objectsa
andb
, the testa == b
returnsTrue
if both arrays are equal in its entirety, including dtype and shape, while the same test withnumpy.ndarray
objects would give a boolean array with element-wise thruth values.The constructor with predefined
dtype
argument can generated via the notationfrozenarray[dtype]
. This is shorthand forlambda base: frozenarray(base, dtype=dtype)
.- Parameters
base (
numpy.ndarray
or array-like) – The array data.dtype – The dtype of the array or
None
.copy (
bool
) – Ifbase
is afrozenarray
and thedtype
matches or isNone
, this argument is ignored. Ifbase
is anumpy.ndarray
and thedtype
matches or isNone
andcopy
isFalse
,base
is stored as is. Otherwisebase
is copied.
-
class
nutils.types.
c_array
(*args, **kwargs)¶ Bases:
object
Converts an array-like object to a ctypes array with a specific dtype. The function
c_array[dtype](array)
returnsarray
unmodified ifarray
is already a ctypes array. Ifarray
is anumpy.ndarray
, the array is converted if thedtype
is correct and the array is contiguous; otherwiseValueError
is raised. Otherwise,array
is first converted to a contiguousnumpy.ndarray
and then converted to ctypes array. In the first two cases changes made to the ctypes array are reflected by thearray
argument: both are essentially views of the same data. In the third case, changes to eitherarray
or the returned ctypes array are not reflected by the other.-
__weakref__
¶ list of weak references to the object (if defined)
-
-
class
nutils.types.
attributes
(**args)¶ Bases:
object
Dictionary-like container with attributes instead of keys, instantiated using keyword arguments:
>>> A = attributes(foo=10, bar=True) >>> A attributes(bar=True, foo=10) >>> A.foo 10
-
__weakref__
¶ list of weak references to the object (if defined)
-
-
class
nutils.types.
unit
(*args, **units)¶ Bases:
object
Framework for physical units.
The unit class provides a basic framework for specifying values with physical units using readable notation such as
2.5km/h
. The system ensures that values are consistent with a measurement system derived from base units, but it does impose or even preload one such system. Instead a derived class, created using eitherunit.create()
or class arguments, should specify the units and scales relevant for the situation to which it is applied.Once units are defined, the formal syntax for instantiating a quantity is:
<quantity> ::= <number> <units> | <number> <operator> <units> <number> ::= "" | <integer> | <integer> "." <integer> ; Numerical value, allowing for decimal fractions but not ; scientific notation. An empty number is equivalent to 1. <units> ::= <unit> | <unit> <operator> <units> <unit> ::= <prefix> <name> <power> <prefix> ::= "" | "h" | "k" | "M" | "G" | "T" | "P" | "E" | "Z" | "Y" | "d" | "c" | "m" | "μ" | "n" | "p" | "f" | "a" | "z" | "y" ; Single character prefix to indicate a multiple or fraction ; of the unit. All SI prefixes are supported except for deca. ; An empty prefix signifies no scaling. <name> ::= <string> ; One of the defined units, case sensitive, containing Latin ; or Greek symbols. <power> ::= "" | <integer> ; Integer power to which to raise the unit. An empty power is ; equivalent to 1. <operator> ::= "*" | "/" ; Multiplication or division.
With the prefix and unit name sharing an alphabet there is potential for ambiguities (is it mol or micro-ol?). These are resolved using the simple logic that the first character is considered part of the unit if this unit exists; otherwise it is considered a prefix.
-
classmethod
create
(*args, **units)¶ Alternative constructor for backwards compatibility.
-
__init__
(*args, **units)¶ Create new unit type.
The unit system is defined via variable keyword arguments, with every unit specified either as a direct numerical value or as a string referencing other units using the standard expression syntax. Ultimately every unit should be resolvable to a numerical value by tracing its dependencies.
The following example defines a subset of the SI system. Note that we cannot use prefixes on the receiving end of a definition for reasons of ambiguity, hence the definition of a gram as 1/1000:
>>> SI = unit(m=1, s=1, g=1e-3, N='kg*m/s2', Pa='N/m2') >>> SI('2km') 2000.0 >>> SI('2g') 0.002
- Parameters
name (
str
(optional, positional only)) – Name of the new class object.**units – Unit definitions.
- Returns
The newly created (uninitiated) unit class.
-
__getitem__
(self, unit)¶ Create subclass of float with custom stringly loads, dumps methods.
-
__call__
(self, s)¶ Create subclass of float and instantiate.
-
__weakref__
¶ list of weak references to the object (if defined)
-
classmethod