Basic Usage¶
In this part, basic usages of TreeValue
will be introduced one by one with sample code and graph to explain them.
Create a tree¶
You can easily create a tree value object based on FastTreeValue
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from treevalue import FastTreeValue t = FastTreeValue({ 'a': 1, 'b': 2.3, 'x': { 'c': 'str', 'd': [1, 2, None], 'e': b'bytes', } }) if __name__ == '__main__': print(t) |
The result should be
1 2 3 4 5 6 7 | <FastTreeValue 0x7fbd617eb460 keys: ['a', 'b', 'x']> ├── 'a' --> 1 ├── 'b' --> 2.3 └── 'x' --> <FastTreeValue 0x7fbd6177fa30 keys: ['c', 'd', 'e']> ├── 'c' --> 'str' ├── 'd' --> [1, 2, None] └── 'e' --> b'bytes' |
Edit the tree¶
After the tree is created, you can access and edit it with __getattr__
, __setattr__
and __delattr__
.
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 | import os from treevalue import FastTreeValue, raw if __name__ == '__main__': t = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}}) print("Original tree:", t, sep=os.linesep) # Get values print("Value of t.a: ", t.a) print("Value of t.x.c:", t.x.c) print("Value of t.x:", t.x, sep=os.linesep) # Set values t.a = 233 print("Value after t.a = 233:", t, sep=os.linesep) t.x.d = -1 print("Value after t.x.d = -1:", t, sep=os.linesep) t.x = {'e': 5, 'f': 6} print("Value after t.x = {'e': 5, 'f': 6}:", t, sep=os.linesep) t.x.g = raw({'e': 5, 'f': 6}) print("Value after t.x.g = raw({'e': 5, 'f': 6}):", t, sep=os.linesep) # Delete values del t.x.g print("Value after del t.x.g:", t, sep=os.linesep) |
The result should be
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | Original tree: <FastTreeValue 0x7f8f9fd99e80 keys: ['a', 'b', 'x']> ├── 'a' --> 1 ├── 'b' --> 2 └── 'x' --> <FastTreeValue 0x7f8fa09ffa30 keys: ['c', 'd']> ├── 'c' --> 3 └── 'd' --> 4 Value of t.a: 1 Value of t.x.c: 3 Value of t.x: <FastTreeValue 0x7f8fa09ffa30 keys: ['c', 'd']> ├── 'c' --> 3 └── 'd' --> 4 Value after t.a = 233: <FastTreeValue 0x7f8f9fd99e80 keys: ['a', 'b', 'x']> ├── 'a' --> 233 ├── 'b' --> 2 └── 'x' --> <FastTreeValue 0x7f8fa09ffa30 keys: ['c', 'd']> ├── 'c' --> 3 └── 'd' --> 4 Value after t.x.d = -1: <FastTreeValue 0x7f8f9fd99e80 keys: ['a', 'b', 'x']> ├── 'a' --> 233 ├── 'b' --> 2 └── 'x' --> <FastTreeValue 0x7f8fa09ffa30 keys: ['c', 'd']> ├── 'c' --> 3 └── 'd' --> -1 Value after t.x = {'e': 5, 'f': 6}: <FastTreeValue 0x7f8f9fd99e80 keys: ['a', 'b', 'x']> ├── 'a' --> 233 ├── 'b' --> 2 └── 'x' --> <FastTreeValue 0x7f8f9fdb0070 keys: ['e', 'f']> ├── 'e' --> 5 └── 'f' --> 6 Value after t.x.g = raw({'e': 5, 'f': 6}): <FastTreeValue 0x7f8f9fd99e80 keys: ['a', 'b', 'x']> ├── 'a' --> 233 ├── 'b' --> 2 └── 'x' --> <FastTreeValue 0x7f8f9fdb0070 keys: ['e', 'f', 'g']> ├── 'e' --> 5 ├── 'f' --> 6 └── 'g' --> {'e': 5, 'f': 6} Value after del t.x.g: <FastTreeValue 0x7f8f9fd99e80 keys: ['a', 'b', 'x']> ├── 'a' --> 233 ├── 'b' --> 2 └── 'x' --> <FastTreeValue 0x7f8f9fdb0070 keys: ['e', 'f']> ├── 'e' --> 5 └── 'f' --> 6 |
The values on the tree has been changed or deleted properly.
And the full life circle of the tree t
is like below.
Do index or slice calculation on the tree¶
Index and slice index operation can be applied all once, like the example below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import os from treevalue import FastTreeValue if __name__ == '__main__': t = FastTreeValue({ 'a': [1, 2, 3], 'b': [4, 9, 16], 'x': { 'c': [11, 13, 17], 'd': [-2, -4, -8] } }) print("Result of t[0]:", t[0], sep=os.linesep) # __getitem__ operator print("Result of t[::-1]:", t[::-1], sep=os.linesep) print("Result of t.x[1:]:", t.x[1:], sep=os.linesep) |
The result should be
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | Result of t[0]: <FastTreeValue 0x7ff5ea175100 keys: ['a', 'b', 'x']> ├── 'a' --> 1 ├── 'b' --> 4 └── 'x' --> <FastTreeValue 0x7ff5ea172af0 keys: ['c', 'd']> ├── 'c' --> 11 └── 'd' --> -2 Result of t[::-1]: <FastTreeValue 0x7ff5ea162430 keys: ['a', 'b', 'x']> ├── 'a' --> [3, 2, 1] ├── 'b' --> [16, 9, 4] └── 'x' --> <FastTreeValue 0x7ff5ea0fb040 keys: ['c', 'd']> ├── 'c' --> [17, 13, 11] └── 'd' --> [-8, -4, -2] Result of t.x[1:]: <FastTreeValue 0x7ff5ea0fb640 keys: ['c', 'd']> ├── 'c' --> [13, 17] └── 'd' --> [-4, -8] |
The structures oof the trees is like the graph below.
Do calculation on the tree¶
Common calculation is supported in treevalue.
1 2 3 4 5 6 7 8 9 10 11 12 | import os from treevalue import FastTreeValue if __name__ == '__main__': t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}}) t2 = FastTreeValue({'a': 3, 'b': 7, 'x': {'c': 14, 'd': -5}}) print("Result of t1 + t2:", t1 + t2, sep=os.linesep) # __add__ operator print("Result of t1 - t2:", t1 - t2, sep=os.linesep) # __sub__ operator print("Result of t1 ^ t2:", t1 ^ t2, sep=os.linesep) # __xor__ operator print("Result of t1 + t2 * (-4 + t1 ** t2)", t1 + t2 * (-4 + t1 ** -t2)) # mathematics calculation |
The result should be
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 | Result of t1 + t2: <FastTreeValue 0x7f963b4d5520 keys: ['a', 'b', 'x']> ├── 'a' --> 4 ├── 'b' --> 9 └── 'x' --> <FastTreeValue 0x7f963b4ccb80 keys: ['c', 'd']> ├── 'c' --> 17 └── 'd' --> -1 Result of t1 - t2: <FastTreeValue 0x7f963b45e400 keys: ['a', 'b', 'x']> ├── 'a' --> -2 ├── 'b' --> -5 └── 'x' --> <FastTreeValue 0x7f963b45e4c0 keys: ['c', 'd']> ├── 'c' --> -11 └── 'd' --> 9 Result of t1 ^ t2: <FastTreeValue 0x7f963b45ea90 keys: ['a', 'b', 'x']> ├── 'a' --> 2 ├── 'b' --> 5 └── 'x' --> <FastTreeValue 0x7f963b45eb50 keys: ['c', 'd']> ├── 'c' --> 13 └── 'd' --> -1 Result of t1 + t2 * (-4 + t1 ** t2) <FastTreeValue 0x7f963b467520 keys: ['a', 'b', 'x']> ├── 'a' --> -8.0 ├── 'b' --> -25.9453125 └── 'x' --> <FastTreeValue 0x7f963b467910 keys: ['c', 'd']> ├── 'c' --> -52.999997072947785 └── 'd' --> -5096 |
The values is processed one to one between the tree.
The structures of the trees involved in __add__
calculation is like below.
Actually, More common operators are supported in treevalue.
Note
In newer versions of treevalue, self operations are supported like the code below.
import os
from treevalue import FastTreeValue
if __name__ == '__main__':
t1 = FastTreeValue({'a': 1, 'b': 2, 'x': {'c': 3, 'd': 4}})
t2 = FastTreeValue({'a': 3, 'b': 7, 'x': {'c': 14, 'd': -5}})
print('t1:', t1, sep=os.linesep)
print('t2:', t2, sep=os.linesep)
print('t1 + t2:', t1 + t2, sep=os.linesep)
_original_ids = (id(t1), id(t2))
print()
t1 += t2
print('After t1 += t2')
print('t1:', t1, sep=os.linesep)
print('t2:', t2, sep=os.linesep)
assert (id(t1), id(t2)) == _original_ids
The output should be
t1:
<FastTreeValue 0x7f4ea2f59e80 keys: ['a', 'b', 'x']>
├── 'a' --> 1
├── 'b' --> 2
└── 'x' --> <FastTreeValue 0x7f4ea3b40a30 keys: ['c', 'd']>
├── 'c' --> 3
└── 'd' --> 4
t2:
<FastTreeValue 0x7f4ea2f6b070 keys: ['a', 'b', 'x']>
├── 'a' --> 3
├── 'b' --> 7
└── 'x' --> <FastTreeValue 0x7f4ea37adeb0 keys: ['c', 'd']>
├── 'c' --> 14
└── 'd' --> -5
t1 + t2:
<FastTreeValue 0x7f4ea2722760 keys: ['a', 'b', 'x']>
├── 'a' --> 4
├── 'b' --> 9
└── 'x' --> <FastTreeValue 0x7f4ea27173d0 keys: ['c', 'd']>
├── 'c' --> 17
└── 'd' --> -1
After t1 += t2
t1:
<FastTreeValue 0x7f4ea2f59e80 keys: ['a', 'b', 'x']>
├── 'a' --> 4
├── 'b' --> 9
└── 'x' --> <FastTreeValue 0x7f4ea3b40a30 keys: ['c', 'd']>
├── 'c' --> 17
└── 'd' --> -1
t2:
<FastTreeValue 0x7f4ea2f6b070 keys: ['a', 'b', 'x']>
├── 'a' --> 3
├── 'b' --> 7
└── 'x' --> <FastTreeValue 0x7f4ea37adeb0 keys: ['c', 'd']>
├── 'c' --> 14
└── 'd' --> -5
We can see that when t1 + t2
is called, a new tree with the sums will be created without t1
’s change, but when t1 += t2
is called, the values in t1
will be replaced to the sums.
Make function tree supported¶
Sometimes we need to do some complex calculation which are not able to be represented by raw operators.
In this situation, we can wrap the common function to tree supported function like the code below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import os from treevalue import FastTreeValue, func_treelize @func_treelize() def gcd(a, b): # GCD calculation while True: r = a % b a, b = b, r if r == 0: break return a if __name__ == '__main__': t1 = FastTreeValue({'a': 2, 'b': 30, 'x': {'c': 4, 'd': 9}}) t2 = FastTreeValue({'a': 4, 'b': 48, 'x': {'c': 6, 'd': 54}}) print("Result of gcd(t1, t2):", gcd(t1, t2), sep=os.linesep) print("Result of gcd(12, 9):", gcd(12, 9)) |
The result should be
1 2 3 4 5 6 7 8 9 | Result of gcd(t1, t2): <TreeValue 0x7f2cfb5d0520 keys: ['a', 'b', 'x']> ├── 'a' --> 2 ├── 'b' --> 6 └── 'x' --> <TreeValue 0x7f2cfb5c8b80 keys: ['c', 'd']> ├── 'c' --> 2 └── 'd' --> 9 Result of gcd(12, 9): 3 |
Luckily, the wrapped function can still used as the original function as well.
The structure of the trees in this part is like below.
Besides, the func_treelize
function will never change the original logical properties of the original function. In the example below, the calculation with original values instead of usage of the trees can be processed properly with the result of the primitive value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from treevalue import func_treelize @func_treelize() def gcd(a, b): # GCD calculation while True: r = a % b a, b = b, r if r == 0: break return a if __name__ == '__main__': print("gcd(6, 8):", gcd(6, 8)) print("gcd(900, 768):", gcd(900, 768)) |
The output should be like below, the gcd
function can still support the greatest common divisor of the primitive integers.
1 2 | gcd(6, 8): 2 gcd(900, 768): 12 |
For further information of how the tree-supported function works, take a look at How the treelized function works , this note may give you more information.