memory-graph 0.3.53__tar.gz → 0.3.54__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {memory_graph-0.3.53/memory_graph.egg-info → memory_graph-0.3.54}/PKG-INFO +33 -23
- {memory_graph-0.3.53 → memory_graph-0.3.54}/README.md +32 -22
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/binary.py +1 -1
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/__init__.py +1 -1
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/config.py +1 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/config_default.py +6 -4
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/config_helpers.py +8 -1
- {memory_graph-0.3.53 → memory_graph-0.3.54/memory_graph.egg-info}/PKG-INFO +33 -23
- {memory_graph-0.3.53 → memory_graph-0.3.54}/pyproject.toml +1 -1
- {memory_graph-0.3.53 → memory_graph-0.3.54}/LICENSE.txt +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/MANIFEST.in +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/add_one.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/add_one.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/avltree.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/avltree_dir.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/avltree_fail.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/avltree_key_value.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/avltree_leaf.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/avltree_linear.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/avltree_table.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/bin_search.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/bin_search.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/bin_search_linear.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/bin_tree.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/bin_tree.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/bin_tree.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/binary.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/colab_example.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_immutable.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_immutable.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_method.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_method.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_mix.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_mix.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_mutable.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/copy_mutable.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/create_gif.sh +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/create_images.sh +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/debug_vscode.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/debugging.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/debugging.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/embedded1.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/embedded2.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/extension_numpy.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/extension_numpy.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/extension_pandas.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/extension_pandas.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/extension_torch.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/extension_torch.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/factorial.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/factorial.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/hash_set.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/hash_set.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/hash_set.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/hidden_edges.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/hidden_edges.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/immutable.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/immutable1.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/immutable2.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/introspect_depth.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/introspect_depth.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/ipython.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/jupyter_example.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/linked_list.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/linked_list.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/linked_list.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/many_types.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/many_types.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/marimo_example.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/memory_graph_web_debugger.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/mutable.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/mutable1.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/mutable2.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/name_rebinding.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/not_node_types.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/power_set.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/power_set.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/rebinding1.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/rebinding2.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/uva.png +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/images/vscode_copying.gif +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/call_stack.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/extension_numpy.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/extension_pandas.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/extension_torch.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/html_table.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/list_view.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/memory_to_nodes.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/node_base.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/node_key_value.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/node_leaf.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/node_linear.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/node_table.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/sequence.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/slicer.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/slices.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/slices_iterator.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/slices_table_iterator.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test_max_graph_depth.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test_memory_graph.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test_memory_to_nodes.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test_sequence.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test_slicer.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test_slices.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/test_slices_iterator.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph/utils.py +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph.egg-info/SOURCES.txt +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph.egg-info/dependency_links.txt +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph.egg-info/requires.txt +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/memory_graph.egg-info/top_level.txt +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/setup.cfg +0 -0
- {memory_graph-0.3.53 → memory_graph-0.3.54}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.54
|
|
4
4
|
Summary: Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.
|
|
5
5
|
Author-email: Bas Terwijn <bterwijn@gmail.com>
|
|
6
6
|
License: BSD 2-Clause License
|
|
@@ -52,7 +52,7 @@ Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
|
52
52
|
|
|
53
53
|
# Highlights #
|
|
54
54
|

|
|
55
|
-
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#play) 👈 now, no installation required!
|
|
55
|
+
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1×tep=1.0&play) 👈 now, no installation required!
|
|
56
56
|
|
|
57
57
|
- learn the right **mental model** to think about Python data (references, mutability, shallow vs deep copy)
|
|
58
58
|
- **visualize the structure of your data** to easily understand and debug any data structure
|
|
@@ -164,8 +164,6 @@ A better way to understand what values are shared is to draw a graph using [memo
|
|
|
164
164
|
|
|
165
165
|
[Troubleshooting](#troubleshooting)
|
|
166
166
|
|
|
167
|
-
[Social Media](#social-media)
|
|
168
|
-
|
|
169
167
|
[Other Packages](#other-packages)
|
|
170
168
|
|
|
171
169
|
## Author ##
|
|
@@ -174,6 +172,10 @@ Bas Terwijn
|
|
|
174
172
|
## Inspiration ##
|
|
175
173
|
Inspired by [Python Tutor](https://pythontutor.com/).
|
|
176
174
|
|
|
175
|
+
## Social Media #
|
|
176
|
+
* LinkedIn: https://www.linkedin.com/groups/13244150/
|
|
177
|
+
* Reddit: https://www.reddit.com/r/Python_memory_graph/
|
|
178
|
+
|
|
177
179
|
## Supported by ##
|
|
178
180
|
<img src="https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/uva.png" alt="University of Amsterdam" width="600">
|
|
179
181
|
|
|
@@ -274,6 +276,8 @@ mg.show(locals())
|
|
|
274
276
|
```
|
|
275
277
|

|
|
276
278
|
|
|
279
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/custom_copy.py&breakpoints=15&continues=1&play).
|
|
280
|
+
|
|
277
281
|
## Name Rebinding ##
|
|
278
282
|
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only rebind the name `b` to another value without effecting any other variables.
|
|
279
283
|
|
|
@@ -348,6 +352,8 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
348
352
|
```
|
|
349
353
|

|
|
350
354
|
|
|
355
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/function_call.py&play).
|
|
356
|
+
|
|
351
357
|
In the printed output only `a` is changed as a result of the function call:
|
|
352
358
|
```
|
|
353
359
|
a:[4, 3, 2, 1] b:(4, 3, 2) c:[4, 3, 2]
|
|
@@ -355,6 +361,8 @@ a:[4, 3, 2, 1] b:(4, 3, 2) c:[4, 3, 2]
|
|
|
355
361
|
|
|
356
362
|
This is because `b` is of immutable type 'tuple' so its value gets copied automatically when it is changed. And because the function is called with a copy of `c`, its original value is not changed by the function. The value of variable `a` is the only value of mutable type that is shared between the root stack frame **'0: \<module>'** and the **'1: add_one'** stack frame of the function so only that variable is affected as a result of the function call. The other changes remain confined to the local variables of the ```add_one()``` function.
|
|
357
363
|
|
|
364
|
+
Now is a good time to practice the Python Data Model. Here are [some exercises](https://github.com/bterwijn/memory_graph_videos/blob/main/exercises/exercises.md) on references, mutability, copies, and function calls.
|
|
365
|
+
|
|
358
366
|
## Block ##
|
|
359
367
|
It is often helpful to temporarily block program execution to inspect the graph. For this we can use the `mg.block()` function:
|
|
360
368
|
|
|
@@ -384,16 +392,17 @@ def factorial(n):
|
|
|
384
392
|
|
|
385
393
|
print( factorial(4) )
|
|
386
394
|
```
|
|
387
|
-
|
|
388
395
|

|
|
389
396
|
|
|
390
397
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
391
398
|
|
|
392
|
-
|
|
399
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/factorial.py×tep=1.0&play).
|
|
400
|
+
|
|
401
|
+
## Binary Convert ##
|
|
393
402
|
A more interesting recursive example is function `binary()` that converts a decimal integer to binary representation.
|
|
394
403
|
```python
|
|
395
404
|
import memory_graph as mg
|
|
396
|
-
mg.config.
|
|
405
|
+
mg.config.type_to_horizontal[list] = True # horizontal lists
|
|
397
406
|
|
|
398
407
|
def binary(value: int) -> list[int]:
|
|
399
408
|
mg.block(mg.show(), mg.stack())
|
|
@@ -411,6 +420,8 @@ print( binary(100) )
|
|
|
411
420
|
1100100
|
|
412
421
|
```
|
|
413
422
|
|
|
423
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/binary_convert.py×tep=1.0&play).
|
|
424
|
+
|
|
414
425
|
## Power Set ##
|
|
415
426
|
A more complex recursive example is function `power_set()` where lists are shared by different function calls. A power set is the set of all subsets of a collection of values.
|
|
416
427
|
|
|
@@ -639,10 +650,10 @@ for i in range(n):
|
|
|
639
650
|
Here we show values being inserted in a HashSet in PyCharm. When inserting the last value '44' we "Step Into" the code to show more of the details.
|
|
640
651
|

|
|
641
652
|
|
|
642
|
-
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py×tep=0.
|
|
653
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py&breakpoints=32&continues=1×tep=0.5&play).
|
|
643
654
|
|
|
644
655
|
# Configuration #
|
|
645
|
-
Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'.
|
|
656
|
+
Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'. The Memory Graph Web Debugger gives examples of the [most important configurations](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/config.py&play).
|
|
646
657
|
|
|
647
658
|
- ***mg.config.reopen_viewer*** : bool
|
|
648
659
|
- If True the viewer is reopened each time show() is called, this might change window focus, default True.
|
|
@@ -677,8 +688,8 @@ Different aspects of memory_graph can be configured. The default configuration c
|
|
|
677
688
|
- ***mg.config.type_to_color*** : dict[type, color]
|
|
678
689
|
- Maps a type to the [graphviz color](https://graphviz.org/doc/info/colors.html) it gets in the graph.
|
|
679
690
|
|
|
680
|
-
- ***mg.config.
|
|
681
|
-
- Maps a type to its orientation. Use 'True' for
|
|
691
|
+
- ***mg.config.type_to_horizontal*** : dict[type, bool]
|
|
692
|
+
- Maps a type to its orientation for Node_Linear and Node_Key_Value. Use 'True' for horizontal and 'False' for vertical. If not specified these nodes vertical unless they have references to children.
|
|
682
693
|
|
|
683
694
|
- ***mg.config.type_to_slicer*** : dict[type, int]
|
|
684
695
|
- Maps a type to a Slicer. A slicer determines how many elements of a data type are shown in the graph to prevent the graph from getting too big. 'Slicer()' does no slicing, 'Slicer(1,2,3)' shows just 1 element at the beginning, 2 in the middle, and 3 at the end.
|
|
@@ -735,7 +746,6 @@ mg.show(locals())
|
|
|
735
746
|
```
|
|
736
747
|

|
|
737
748
|
|
|
738
|
-
|
|
739
749
|
## All attributes using dir() ##
|
|
740
750
|
A useful start is to give it some color, show the list of all its attributes using `dir()`, and setting an empty Slicer to see the attribute list in full.
|
|
741
751
|
|
|
@@ -757,7 +767,7 @@ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.Slicer()
|
|
|
757
767
|
|
|
758
768
|
mg.show(locals())
|
|
759
769
|
```
|
|
760
|
-

|
|
761
771
|
|
|
762
772
|
Next figure out what the attributes are you want to graph and choose a Node type, there are four options:
|
|
763
773
|
|
|
@@ -780,7 +790,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Leaf(data,
|
|
|
780
790
|
|
|
781
791
|
mg.show(locals())
|
|
782
792
|
```
|
|
783
|
-

|
|
784
794
|
|
|
785
795
|
## 2) Node_Linear ##
|
|
786
796
|
Node_Linear shows multiple values in a line like a list.
|
|
@@ -804,7 +814,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Linear(data
|
|
|
804
814
|
|
|
805
815
|
mg.show(locals())
|
|
806
816
|
```
|
|
807
|
-

|
|
808
818
|
|
|
809
819
|
## 3) Node_Key_Value ##
|
|
810
820
|
Node_Key_Value shows key-value pairs like a dictionary. Note the required `items()` call at the end.
|
|
@@ -828,7 +838,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Key_Value(d
|
|
|
828
838
|
|
|
829
839
|
mg.show(locals())
|
|
830
840
|
```
|
|
831
|
-

|
|
832
842
|
|
|
833
843
|
## 4) Node_Table ##
|
|
834
844
|
Node_Table shows all the values as a table.
|
|
@@ -850,7 +860,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Table(data,
|
|
|
850
860
|
|
|
851
861
|
mg.show(locals())
|
|
852
862
|
```
|
|
853
|
-

|
|
854
864
|
|
|
855
865
|
## Binary Search ##
|
|
856
866
|
For binary search we can use a List_View class to represent a particular sublist without making a list copy.
|
|
@@ -955,7 +965,7 @@ mg.config.type_to_depth[B] = 3
|
|
|
955
965
|
mg.config.type_to_depth[id(c)] = 2
|
|
956
966
|
mg.show(locals())
|
|
957
967
|
```
|
|
958
|
-

|
|
959
969
|
|
|
960
970
|
## Hidden Edges ##
|
|
961
971
|
|
|
@@ -971,7 +981,7 @@ for i in range(20):
|
|
|
971
981
|
|
|
972
982
|
mg.show(locals())
|
|
973
983
|
```
|
|
974
|
-

|
|
975
985
|
|
|
976
986
|
# Extensions #
|
|
977
987
|
Different extensions are available for types from other Python packages.
|
|
@@ -994,6 +1004,8 @@ mg.show(locals())
|
|
|
994
1004
|
```
|
|
995
1005
|

|
|
996
1006
|
|
|
1007
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=numpy&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_numpy.py&continues=1).
|
|
1008
|
+
|
|
997
1009
|
## Pandas ##
|
|
998
1010
|
Pandas types `Series` and `DataFrame` can be graphed with "memory_graph.extension_pandas":
|
|
999
1011
|
|
|
@@ -1013,6 +1025,8 @@ mg.show(locals())
|
|
|
1013
1025
|
```
|
|
1014
1026
|

|
|
1015
1027
|
|
|
1028
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=pandas&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_pandas.py&continues=1).
|
|
1029
|
+
|
|
1016
1030
|
## PyTorch ##
|
|
1017
1031
|
Torch type `tensor` can be graphed with "memory_graph.extension_torch":
|
|
1018
1032
|
|
|
@@ -1091,9 +1105,5 @@ $ bash create_gif.sh animated
|
|
|
1091
1105
|
|
|
1092
1106
|
- When graph edges overlap it can be hard to distinguish them. Using an interactive graphviz viewer, such as [xdot](https://github.com/jrfonseca/xdot.py), on a '*.gv' DOT output file will help.
|
|
1093
1107
|
|
|
1094
|
-
# Social Media #
|
|
1095
|
-
* LinkedIn: https://www.linkedin.com/groups/13244150/
|
|
1096
|
-
* Reddit: https://www.reddit.com/r/Python_memory_graph/
|
|
1097
|
-
|
|
1098
1108
|
# Other Packages #
|
|
1099
1109
|
The [memory_graph](https://pypi.org/project/memory-graph/) package visualizes your data. If instead you want to visualize function calls, check out the [invocation_tree](https://pypi.org/project/invocation-tree/) package.
|
|
@@ -7,7 +7,7 @@ Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
|
7
7
|
|
|
8
8
|
# Highlights #
|
|
9
9
|

|
|
10
|
-
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#play) 👈 now, no installation required!
|
|
10
|
+
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1×tep=1.0&play) 👈 now, no installation required!
|
|
11
11
|
|
|
12
12
|
- learn the right **mental model** to think about Python data (references, mutability, shallow vs deep copy)
|
|
13
13
|
- **visualize the structure of your data** to easily understand and debug any data structure
|
|
@@ -119,8 +119,6 @@ A better way to understand what values are shared is to draw a graph using [memo
|
|
|
119
119
|
|
|
120
120
|
[Troubleshooting](#troubleshooting)
|
|
121
121
|
|
|
122
|
-
[Social Media](#social-media)
|
|
123
|
-
|
|
124
122
|
[Other Packages](#other-packages)
|
|
125
123
|
|
|
126
124
|
## Author ##
|
|
@@ -129,6 +127,10 @@ Bas Terwijn
|
|
|
129
127
|
## Inspiration ##
|
|
130
128
|
Inspired by [Python Tutor](https://pythontutor.com/).
|
|
131
129
|
|
|
130
|
+
## Social Media #
|
|
131
|
+
* LinkedIn: https://www.linkedin.com/groups/13244150/
|
|
132
|
+
* Reddit: https://www.reddit.com/r/Python_memory_graph/
|
|
133
|
+
|
|
132
134
|
## Supported by ##
|
|
133
135
|
<img src="https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/uva.png" alt="University of Amsterdam" width="600">
|
|
134
136
|
|
|
@@ -229,6 +231,8 @@ mg.show(locals())
|
|
|
229
231
|
```
|
|
230
232
|

|
|
231
233
|
|
|
234
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/custom_copy.py&breakpoints=15&continues=1&play).
|
|
235
|
+
|
|
232
236
|
## Name Rebinding ##
|
|
233
237
|
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only rebind the name `b` to another value without effecting any other variables.
|
|
234
238
|
|
|
@@ -303,6 +307,8 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
303
307
|
```
|
|
304
308
|

|
|
305
309
|
|
|
310
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/function_call.py&play).
|
|
311
|
+
|
|
306
312
|
In the printed output only `a` is changed as a result of the function call:
|
|
307
313
|
```
|
|
308
314
|
a:[4, 3, 2, 1] b:(4, 3, 2) c:[4, 3, 2]
|
|
@@ -310,6 +316,8 @@ a:[4, 3, 2, 1] b:(4, 3, 2) c:[4, 3, 2]
|
|
|
310
316
|
|
|
311
317
|
This is because `b` is of immutable type 'tuple' so its value gets copied automatically when it is changed. And because the function is called with a copy of `c`, its original value is not changed by the function. The value of variable `a` is the only value of mutable type that is shared between the root stack frame **'0: \<module>'** and the **'1: add_one'** stack frame of the function so only that variable is affected as a result of the function call. The other changes remain confined to the local variables of the ```add_one()``` function.
|
|
312
318
|
|
|
319
|
+
Now is a good time to practice the Python Data Model. Here are [some exercises](https://github.com/bterwijn/memory_graph_videos/blob/main/exercises/exercises.md) on references, mutability, copies, and function calls.
|
|
320
|
+
|
|
313
321
|
## Block ##
|
|
314
322
|
It is often helpful to temporarily block program execution to inspect the graph. For this we can use the `mg.block()` function:
|
|
315
323
|
|
|
@@ -339,16 +347,17 @@ def factorial(n):
|
|
|
339
347
|
|
|
340
348
|
print( factorial(4) )
|
|
341
349
|
```
|
|
342
|
-
|
|
343
350
|

|
|
344
351
|
|
|
345
352
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
346
353
|
|
|
347
|
-
|
|
354
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/factorial.py×tep=1.0&play).
|
|
355
|
+
|
|
356
|
+
## Binary Convert ##
|
|
348
357
|
A more interesting recursive example is function `binary()` that converts a decimal integer to binary representation.
|
|
349
358
|
```python
|
|
350
359
|
import memory_graph as mg
|
|
351
|
-
mg.config.
|
|
360
|
+
mg.config.type_to_horizontal[list] = True # horizontal lists
|
|
352
361
|
|
|
353
362
|
def binary(value: int) -> list[int]:
|
|
354
363
|
mg.block(mg.show(), mg.stack())
|
|
@@ -366,6 +375,8 @@ print( binary(100) )
|
|
|
366
375
|
1100100
|
|
367
376
|
```
|
|
368
377
|
|
|
378
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/binary_convert.py×tep=1.0&play).
|
|
379
|
+
|
|
369
380
|
## Power Set ##
|
|
370
381
|
A more complex recursive example is function `power_set()` where lists are shared by different function calls. A power set is the set of all subsets of a collection of values.
|
|
371
382
|
|
|
@@ -594,10 +605,10 @@ for i in range(n):
|
|
|
594
605
|
Here we show values being inserted in a HashSet in PyCharm. When inserting the last value '44' we "Step Into" the code to show more of the details.
|
|
595
606
|

|
|
596
607
|
|
|
597
|
-
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py×tep=0.
|
|
608
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py&breakpoints=32&continues=1×tep=0.5&play).
|
|
598
609
|
|
|
599
610
|
# Configuration #
|
|
600
|
-
Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'.
|
|
611
|
+
Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'. The Memory Graph Web Debugger gives examples of the [most important configurations](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/config.py&play).
|
|
601
612
|
|
|
602
613
|
- ***mg.config.reopen_viewer*** : bool
|
|
603
614
|
- If True the viewer is reopened each time show() is called, this might change window focus, default True.
|
|
@@ -632,8 +643,8 @@ Different aspects of memory_graph can be configured. The default configuration c
|
|
|
632
643
|
- ***mg.config.type_to_color*** : dict[type, color]
|
|
633
644
|
- Maps a type to the [graphviz color](https://graphviz.org/doc/info/colors.html) it gets in the graph.
|
|
634
645
|
|
|
635
|
-
- ***mg.config.
|
|
636
|
-
- Maps a type to its orientation. Use 'True' for
|
|
646
|
+
- ***mg.config.type_to_horizontal*** : dict[type, bool]
|
|
647
|
+
- Maps a type to its orientation for Node_Linear and Node_Key_Value. Use 'True' for horizontal and 'False' for vertical. If not specified these nodes vertical unless they have references to children.
|
|
637
648
|
|
|
638
649
|
- ***mg.config.type_to_slicer*** : dict[type, int]
|
|
639
650
|
- Maps a type to a Slicer. A slicer determines how many elements of a data type are shown in the graph to prevent the graph from getting too big. 'Slicer()' does no slicing, 'Slicer(1,2,3)' shows just 1 element at the beginning, 2 in the middle, and 3 at the end.
|
|
@@ -690,7 +701,6 @@ mg.show(locals())
|
|
|
690
701
|
```
|
|
691
702
|

|
|
692
703
|
|
|
693
|
-
|
|
694
704
|
## All attributes using dir() ##
|
|
695
705
|
A useful start is to give it some color, show the list of all its attributes using `dir()`, and setting an empty Slicer to see the attribute list in full.
|
|
696
706
|
|
|
@@ -712,7 +722,7 @@ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.Slicer()
|
|
|
712
722
|
|
|
713
723
|
mg.show(locals())
|
|
714
724
|
```
|
|
715
|
-

|
|
716
726
|
|
|
717
727
|
Next figure out what the attributes are you want to graph and choose a Node type, there are four options:
|
|
718
728
|
|
|
@@ -735,7 +745,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Leaf(data,
|
|
|
735
745
|
|
|
736
746
|
mg.show(locals())
|
|
737
747
|
```
|
|
738
|
-

|
|
739
749
|
|
|
740
750
|
## 2) Node_Linear ##
|
|
741
751
|
Node_Linear shows multiple values in a line like a list.
|
|
@@ -759,7 +769,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Linear(data
|
|
|
759
769
|
|
|
760
770
|
mg.show(locals())
|
|
761
771
|
```
|
|
762
|
-

|
|
763
773
|
|
|
764
774
|
## 3) Node_Key_Value ##
|
|
765
775
|
Node_Key_Value shows key-value pairs like a dictionary. Note the required `items()` call at the end.
|
|
@@ -783,7 +793,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Key_Value(d
|
|
|
783
793
|
|
|
784
794
|
mg.show(locals())
|
|
785
795
|
```
|
|
786
|
-

|
|
787
797
|
|
|
788
798
|
## 4) Node_Table ##
|
|
789
799
|
Node_Table shows all the values as a table.
|
|
@@ -805,7 +815,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Table(data,
|
|
|
805
815
|
|
|
806
816
|
mg.show(locals())
|
|
807
817
|
```
|
|
808
|
-

|
|
809
819
|
|
|
810
820
|
## Binary Search ##
|
|
811
821
|
For binary search we can use a List_View class to represent a particular sublist without making a list copy.
|
|
@@ -910,7 +920,7 @@ mg.config.type_to_depth[B] = 3
|
|
|
910
920
|
mg.config.type_to_depth[id(c)] = 2
|
|
911
921
|
mg.show(locals())
|
|
912
922
|
```
|
|
913
|
-

|
|
914
924
|
|
|
915
925
|
## Hidden Edges ##
|
|
916
926
|
|
|
@@ -926,7 +936,7 @@ for i in range(20):
|
|
|
926
936
|
|
|
927
937
|
mg.show(locals())
|
|
928
938
|
```
|
|
929
|
-

|
|
930
940
|
|
|
931
941
|
# Extensions #
|
|
932
942
|
Different extensions are available for types from other Python packages.
|
|
@@ -949,6 +959,8 @@ mg.show(locals())
|
|
|
949
959
|
```
|
|
950
960
|

|
|
951
961
|
|
|
962
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=numpy&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_numpy.py&continues=1).
|
|
963
|
+
|
|
952
964
|
## Pandas ##
|
|
953
965
|
Pandas types `Series` and `DataFrame` can be graphed with "memory_graph.extension_pandas":
|
|
954
966
|
|
|
@@ -968,6 +980,8 @@ mg.show(locals())
|
|
|
968
980
|
```
|
|
969
981
|

|
|
970
982
|
|
|
983
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=pandas&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_pandas.py&continues=1).
|
|
984
|
+
|
|
971
985
|
## PyTorch ##
|
|
972
986
|
Torch type `tensor` can be graphed with "memory_graph.extension_torch":
|
|
973
987
|
|
|
@@ -1046,9 +1060,5 @@ $ bash create_gif.sh animated
|
|
|
1046
1060
|
|
|
1047
1061
|
- When graph edges overlap it can be hard to distinguish them. Using an interactive graphviz viewer, such as [xdot](https://github.com/jrfonseca/xdot.py), on a '*.gv' DOT output file will help.
|
|
1048
1062
|
|
|
1049
|
-
# Social Media #
|
|
1050
|
-
* LinkedIn: https://www.linkedin.com/groups/13244150/
|
|
1051
|
-
* Reddit: https://www.reddit.com/r/Python_memory_graph/
|
|
1052
|
-
|
|
1053
1063
|
# Other Packages #
|
|
1054
1064
|
The [memory_graph](https://pypi.org/project/memory-graph/) package visualizes your data. If instead you want to visualize function calls, check out the [invocation_tree](https://pypi.org/project/invocation-tree/) package.
|
|
@@ -103,10 +103,12 @@ def reset():
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
""" Types that will be visualized in vertical orientation
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
106
|
+
""" Types that will be visualized in horizontal or vertical orientation based on a True/False value.
|
|
107
|
+
The 'type_to_horizontal' takes precedence over 'type_to_vertical'.
|
|
108
|
+
If no boolean value is present the Node decides based on it having references."""
|
|
109
|
+
config.type_to_horizontal = {}
|
|
110
|
+
config.type_to_vertical = {}
|
|
111
|
+
|
|
110
112
|
|
|
111
113
|
""" Slicer objects for different types. """
|
|
112
114
|
config.type_to_slicer = {
|
|
@@ -23,10 +23,17 @@ def get_color(node, default='white'):
|
|
|
23
23
|
default)
|
|
24
24
|
|
|
25
25
|
def get_vertical(node, default):
|
|
26
|
+
horizontal = get_property(node.get_id(),
|
|
27
|
+
node.get_type(),
|
|
28
|
+
type(node),
|
|
29
|
+
config.type_to_horizontal,
|
|
30
|
+
None)
|
|
31
|
+
if isinstance(horizontal, bool):
|
|
32
|
+
return not horizontal
|
|
26
33
|
return get_property(node.get_id(),
|
|
27
34
|
node.get_type(),
|
|
28
35
|
type(node),
|
|
29
|
-
config.type_to_vertical,
|
|
36
|
+
config.type_to_vertical,
|
|
30
37
|
default)
|
|
31
38
|
|
|
32
39
|
def get_slicer(node, data, default=Slicer(3,2,3)):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.54
|
|
4
4
|
Summary: Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.
|
|
5
5
|
Author-email: Bas Terwijn <bterwijn@gmail.com>
|
|
6
6
|
License: BSD 2-Clause License
|
|
@@ -52,7 +52,7 @@ Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
|
52
52
|
|
|
53
53
|
# Highlights #
|
|
54
54
|

|
|
55
|
-
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#play) 👈 now, no installation required!
|
|
55
|
+
Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph.com/#breakpoints=8&continues=1×tep=1.0&play) 👈 now, no installation required!
|
|
56
56
|
|
|
57
57
|
- learn the right **mental model** to think about Python data (references, mutability, shallow vs deep copy)
|
|
58
58
|
- **visualize the structure of your data** to easily understand and debug any data structure
|
|
@@ -164,8 +164,6 @@ A better way to understand what values are shared is to draw a graph using [memo
|
|
|
164
164
|
|
|
165
165
|
[Troubleshooting](#troubleshooting)
|
|
166
166
|
|
|
167
|
-
[Social Media](#social-media)
|
|
168
|
-
|
|
169
167
|
[Other Packages](#other-packages)
|
|
170
168
|
|
|
171
169
|
## Author ##
|
|
@@ -174,6 +172,10 @@ Bas Terwijn
|
|
|
174
172
|
## Inspiration ##
|
|
175
173
|
Inspired by [Python Tutor](https://pythontutor.com/).
|
|
176
174
|
|
|
175
|
+
## Social Media #
|
|
176
|
+
* LinkedIn: https://www.linkedin.com/groups/13244150/
|
|
177
|
+
* Reddit: https://www.reddit.com/r/Python_memory_graph/
|
|
178
|
+
|
|
177
179
|
## Supported by ##
|
|
178
180
|
<img src="https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/uva.png" alt="University of Amsterdam" width="600">
|
|
179
181
|
|
|
@@ -274,6 +276,8 @@ mg.show(locals())
|
|
|
274
276
|
```
|
|
275
277
|

|
|
276
278
|
|
|
279
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/custom_copy.py&breakpoints=15&continues=1&play).
|
|
280
|
+
|
|
277
281
|
## Name Rebinding ##
|
|
278
282
|
When `a` and `b` share a mutable value, then changing the value of `b` changes the value of `a` and vice versa. However, reassigning `b` does not change `a`. When you reassign `b`, you only rebind the name `b` to another value without effecting any other variables.
|
|
279
283
|
|
|
@@ -348,6 +352,8 @@ print(f"a:{a} b:{b} c:{c}")
|
|
|
348
352
|
```
|
|
349
353
|

|
|
350
354
|
|
|
355
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/function_call.py&play).
|
|
356
|
+
|
|
351
357
|
In the printed output only `a` is changed as a result of the function call:
|
|
352
358
|
```
|
|
353
359
|
a:[4, 3, 2, 1] b:(4, 3, 2) c:[4, 3, 2]
|
|
@@ -355,6 +361,8 @@ a:[4, 3, 2, 1] b:(4, 3, 2) c:[4, 3, 2]
|
|
|
355
361
|
|
|
356
362
|
This is because `b` is of immutable type 'tuple' so its value gets copied automatically when it is changed. And because the function is called with a copy of `c`, its original value is not changed by the function. The value of variable `a` is the only value of mutable type that is shared between the root stack frame **'0: \<module>'** and the **'1: add_one'** stack frame of the function so only that variable is affected as a result of the function call. The other changes remain confined to the local variables of the ```add_one()``` function.
|
|
357
363
|
|
|
364
|
+
Now is a good time to practice the Python Data Model. Here are [some exercises](https://github.com/bterwijn/memory_graph_videos/blob/main/exercises/exercises.md) on references, mutability, copies, and function calls.
|
|
365
|
+
|
|
358
366
|
## Block ##
|
|
359
367
|
It is often helpful to temporarily block program execution to inspect the graph. For this we can use the `mg.block()` function:
|
|
360
368
|
|
|
@@ -384,16 +392,17 @@ def factorial(n):
|
|
|
384
392
|
|
|
385
393
|
print( factorial(4) )
|
|
386
394
|
```
|
|
387
|
-
|
|
388
395
|

|
|
389
396
|
|
|
390
397
|
and the result is: 1 x 2 x 3 x 4 = 24
|
|
391
398
|
|
|
392
|
-
|
|
399
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/factorial.py×tep=1.0&play).
|
|
400
|
+
|
|
401
|
+
## Binary Convert ##
|
|
393
402
|
A more interesting recursive example is function `binary()` that converts a decimal integer to binary representation.
|
|
394
403
|
```python
|
|
395
404
|
import memory_graph as mg
|
|
396
|
-
mg.config.
|
|
405
|
+
mg.config.type_to_horizontal[list] = True # horizontal lists
|
|
397
406
|
|
|
398
407
|
def binary(value: int) -> list[int]:
|
|
399
408
|
mg.block(mg.show(), mg.stack())
|
|
@@ -411,6 +420,8 @@ print( binary(100) )
|
|
|
411
420
|
1100100
|
|
412
421
|
```
|
|
413
422
|
|
|
423
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/binary_convert.py×tep=1.0&play).
|
|
424
|
+
|
|
414
425
|
## Power Set ##
|
|
415
426
|
A more complex recursive example is function `power_set()` where lists are shared by different function calls. A power set is the set of all subsets of a collection of values.
|
|
416
427
|
|
|
@@ -639,10 +650,10 @@ for i in range(n):
|
|
|
639
650
|
Here we show values being inserted in a HashSet in PyCharm. When inserting the last value '44' we "Step Into" the code to show more of the details.
|
|
640
651
|

|
|
641
652
|
|
|
642
|
-
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py×tep=0.
|
|
653
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_set.py&breakpoints=32&continues=1×tep=0.5&play).
|
|
643
654
|
|
|
644
655
|
# Configuration #
|
|
645
|
-
Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'.
|
|
656
|
+
Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'. The Memory Graph Web Debugger gives examples of the [most important configurations](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/config.py&play).
|
|
646
657
|
|
|
647
658
|
- ***mg.config.reopen_viewer*** : bool
|
|
648
659
|
- If True the viewer is reopened each time show() is called, this might change window focus, default True.
|
|
@@ -677,8 +688,8 @@ Different aspects of memory_graph can be configured. The default configuration c
|
|
|
677
688
|
- ***mg.config.type_to_color*** : dict[type, color]
|
|
678
689
|
- Maps a type to the [graphviz color](https://graphviz.org/doc/info/colors.html) it gets in the graph.
|
|
679
690
|
|
|
680
|
-
- ***mg.config.
|
|
681
|
-
- Maps a type to its orientation. Use 'True' for
|
|
691
|
+
- ***mg.config.type_to_horizontal*** : dict[type, bool]
|
|
692
|
+
- Maps a type to its orientation for Node_Linear and Node_Key_Value. Use 'True' for horizontal and 'False' for vertical. If not specified these nodes vertical unless they have references to children.
|
|
682
693
|
|
|
683
694
|
- ***mg.config.type_to_slicer*** : dict[type, int]
|
|
684
695
|
- Maps a type to a Slicer. A slicer determines how many elements of a data type are shown in the graph to prevent the graph from getting too big. 'Slicer()' does no slicing, 'Slicer(1,2,3)' shows just 1 element at the beginning, 2 in the middle, and 3 at the end.
|
|
@@ -735,7 +746,6 @@ mg.show(locals())
|
|
|
735
746
|
```
|
|
736
747
|

|
|
737
748
|
|
|
738
|
-
|
|
739
749
|
## All attributes using dir() ##
|
|
740
750
|
A useful start is to give it some color, show the list of all its attributes using `dir()`, and setting an empty Slicer to see the attribute list in full.
|
|
741
751
|
|
|
@@ -757,7 +767,7 @@ mg.config.type_to_slicer[bintrees.avltree.Node] = mg.Slicer()
|
|
|
757
767
|
|
|
758
768
|
mg.show(locals())
|
|
759
769
|
```
|
|
760
|
-

|
|
761
771
|
|
|
762
772
|
Next figure out what the attributes are you want to graph and choose a Node type, there are four options:
|
|
763
773
|
|
|
@@ -780,7 +790,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Leaf(data,
|
|
|
780
790
|
|
|
781
791
|
mg.show(locals())
|
|
782
792
|
```
|
|
783
|
-

|
|
784
794
|
|
|
785
795
|
## 2) Node_Linear ##
|
|
786
796
|
Node_Linear shows multiple values in a line like a list.
|
|
@@ -804,7 +814,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Linear(data
|
|
|
804
814
|
|
|
805
815
|
mg.show(locals())
|
|
806
816
|
```
|
|
807
|
-

|
|
808
818
|
|
|
809
819
|
## 3) Node_Key_Value ##
|
|
810
820
|
Node_Key_Value shows key-value pairs like a dictionary. Note the required `items()` call at the end.
|
|
@@ -828,7 +838,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Key_Value(d
|
|
|
828
838
|
|
|
829
839
|
mg.show(locals())
|
|
830
840
|
```
|
|
831
|
-

|
|
832
842
|
|
|
833
843
|
## 4) Node_Table ##
|
|
834
844
|
Node_Table shows all the values as a table.
|
|
@@ -850,7 +860,7 @@ mg.config.type_to_node[bintrees.avltree.Node] = lambda data: mg.Node_Table(data,
|
|
|
850
860
|
|
|
851
861
|
mg.show(locals())
|
|
852
862
|
```
|
|
853
|
-

|
|
854
864
|
|
|
855
865
|
## Binary Search ##
|
|
856
866
|
For binary search we can use a List_View class to represent a particular sublist without making a list copy.
|
|
@@ -955,7 +965,7 @@ mg.config.type_to_depth[B] = 3
|
|
|
955
965
|
mg.config.type_to_depth[id(c)] = 2
|
|
956
966
|
mg.show(locals())
|
|
957
967
|
```
|
|
958
|
-

|
|
959
969
|
|
|
960
970
|
## Hidden Edges ##
|
|
961
971
|
|
|
@@ -971,7 +981,7 @@ for i in range(20):
|
|
|
971
981
|
|
|
972
982
|
mg.show(locals())
|
|
973
983
|
```
|
|
974
|
-

|
|
975
985
|
|
|
976
986
|
# Extensions #
|
|
977
987
|
Different extensions are available for types from other Python packages.
|
|
@@ -994,6 +1004,8 @@ mg.show(locals())
|
|
|
994
1004
|
```
|
|
995
1005
|

|
|
996
1006
|
|
|
1007
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=numpy&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_numpy.py&continues=1).
|
|
1008
|
+
|
|
997
1009
|
## Pandas ##
|
|
998
1010
|
Pandas types `Series` and `DataFrame` can be graphed with "memory_graph.extension_pandas":
|
|
999
1011
|
|
|
@@ -1013,6 +1025,8 @@ mg.show(locals())
|
|
|
1013
1025
|
```
|
|
1014
1026
|

|
|
1015
1027
|
|
|
1028
|
+
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#micropip=pandas&codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/mg_pandas.py&continues=1).
|
|
1029
|
+
|
|
1016
1030
|
## PyTorch ##
|
|
1017
1031
|
Torch type `tensor` can be graphed with "memory_graph.extension_torch":
|
|
1018
1032
|
|
|
@@ -1091,9 +1105,5 @@ $ bash create_gif.sh animated
|
|
|
1091
1105
|
|
|
1092
1106
|
- When graph edges overlap it can be hard to distinguish them. Using an interactive graphviz viewer, such as [xdot](https://github.com/jrfonseca/xdot.py), on a '*.gv' DOT output file will help.
|
|
1093
1107
|
|
|
1094
|
-
# Social Media #
|
|
1095
|
-
* LinkedIn: https://www.linkedin.com/groups/13244150/
|
|
1096
|
-
* Reddit: https://www.reddit.com/r/Python_memory_graph/
|
|
1097
|
-
|
|
1098
1108
|
# Other Packages #
|
|
1099
1109
|
The [memory_graph](https://pypi.org/project/memory-graph/) package visualizes your data. If instead you want to visualize function calls, check out the [invocation_tree](https://pypi.org/project/invocation-tree/) package.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "memory_graph"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.54"
|
|
8
8
|
description = "Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy."
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Bas Terwijn", email = "bterwijn@gmail.com"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|