Advanced¶
Memory Efficiency and Meta Data¶
Node uses
__slots__
for improved performance and memory efficiency.
As a side effect, it is not possible to assign new attributes to a node instance.
The meta slot can be used to attach arbitrary key/value pairs to a node.
Use get_meta(), set_meta(),
update_meta(), and clear_meta(),
to modify this node meta data:
node.set_meta("foo", 42)
assert node.get_meta("foo") == 42
node.set_meta("bar", "baz")
assert node._meta == {"foo": 42, "bar": "baz"}
Values are stored in a single dict node._meta, and is not used internally by nutree.
However we should not access it directly, but use the provided methods instead.
The dict stores values _sparse_, i.e. only values != None are stored.
This means that if you set a value to None, it will be removed from the dict.
If the dict is empty, node._meta will be set to None to save memory.
Iteration Callbacks¶
In the following sections we cover Search, Traversal,
Mutation, etc. in detail.
Some methods described there, accept a predicate argument, for example
copy(), filter(),
find_all() …
In all cases, the predicate callback is called with one single node argument and should return control value:
Note
The special values
StopTraversal, SkipBranch,
and SelectBranch can be returned as value or raised
as exception.
The match callback can return these values:
False or None: No match: skip the node and continue traversal.
True: Stop iteration and return this node as result.
StopTraversal: Stop iteration and return None as result.
The match callback can return these values:
False or None: No match: skip the node and continue traversal.
True: Add node to results and continue traversal.
SkipBranch: Skip node and its descendants, but continue iteration with next sibling.
Return SkipBranch(and_self=False) to add the node to results, but skip descendants.
StopTraversal: Stop iteration and return current results.
The callback callback can return these values:
False: Stop iteration immediately.
StopTraversal: Stop iteration immediately. Return or raise StopTraversal(value) to specify a return value for the visit method.
SkipBranch: Skip descendants, but continue iteration with next sibling.True, None, and all other values: No action: continue traversal.
copy(),
filter(),
filtered(),
copy()
The predicate callback can return these values:
True: Keep the node and visit children.
False or None: Visit children and keep this node if at least one descendant is true.
SkipBranch: Skip node and its descendants, but continue iteration with next sibling.
Return SkipBranch(and_self=False) to keep the node, but skip descendants.
SelectBranch: Unconditionally accept node and all descendants (do not call predicate()). In other words: copy the whole branch.
save()
to_dict_list(),
to_dot(),
to_dotfile(),
to_list_iter()
The mapper(node, data) callback can modify the dict argument data in-place (and return None) or return a new dict istance.
Locking¶
In multithreading scenarios, we can enforce critical sections like so:
with tree:
snapshot = tree.to_dict_list()
Debugging¶
Call _self_check() to validate the internal data structures.
This is slow and should not be done in production:
assert tree._self_check()
Performance Optimization¶
Most Node attributes are exposed as readonly properties.
The real attribute is prefixed by an underscore.
In some situations, like close loops in critical algorithms it may be slightly
faster to access attributes directly.
Warning
Use with care. Accessing or even modifying internal attributes may break the internal data structures.
When optimizing:
- Correctness before performance:
Write simple, error free code first and cover it with unit tests, before starting to optimize.
- Correctness before performance:
- Do not guess or assume:
Write benchmarks !
- Do not guess or assume:
File System Helper¶
There is a simple helper that can be used to read a folder recursively:
from nutree import load_tree_from_fs
path = "/my/folder/path"
tree = load_tree_from_fs(path)
tree.print()
Tree</my/folder/path>
├── 'file_1.txt', 13 bytes
╰── [folder_1]
╰── 'file_1_1.txt', 15 bytes