memory-graph 0.3.73__tar.gz → 0.3.74__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.
Files changed (41) hide show
  1. {memory_graph-0.3.73 → memory_graph-0.3.74}/PKG-INFO +116 -11
  2. {memory_graph-0.3.73 → memory_graph-0.3.74}/README.md +115 -10
  3. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/__init__.py +1 -1
  4. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/config.py +7 -4
  5. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/utils.py +1 -0
  6. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph.egg-info/PKG-INFO +116 -11
  7. {memory_graph-0.3.73 → memory_graph-0.3.74}/pyproject.toml +1 -1
  8. {memory_graph-0.3.73 → memory_graph-0.3.74}/LICENSE.txt +0 -0
  9. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/call_stack.py +0 -0
  10. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/config_default.py +0 -0
  11. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/config_helpers.py +0 -0
  12. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/extension_numpy.py +0 -0
  13. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/extension_pandas.py +0 -0
  14. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/extension_torch.py +0 -0
  15. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/html_table.py +0 -0
  16. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/list_view.py +0 -0
  17. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/memory_to_nodes.py +0 -0
  18. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/node_base.py +0 -0
  19. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/node_key_value.py +0 -0
  20. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/node_leaf.py +0 -0
  21. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/node_linear.py +0 -0
  22. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/node_table.py +0 -0
  23. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/sequence.py +0 -0
  24. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/slicer.py +0 -0
  25. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/slices.py +0 -0
  26. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/slices_iterator.py +0 -0
  27. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/slices_table_iterator.py +0 -0
  28. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test.py +0 -0
  29. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test_max_graph_depth.py +0 -0
  30. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test_memory_graph.py +0 -0
  31. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test_memory_to_nodes.py +0 -0
  32. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test_sequence.py +0 -0
  33. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test_slicer.py +0 -0
  34. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test_slices.py +0 -0
  35. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph/test_slices_iterator.py +0 -0
  36. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph.egg-info/SOURCES.txt +0 -0
  37. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph.egg-info/dependency_links.txt +0 -0
  38. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph.egg-info/requires.txt +0 -0
  39. {memory_graph-0.3.73 → memory_graph-0.3.74}/memory_graph.egg-info/top_level.txt +0 -0
  40. {memory_graph-0.3.73 → memory_graph-0.3.74}/setup.cfg +0 -0
  41. {memory_graph-0.3.73 → memory_graph-0.3.74}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memory_graph
3
- Version: 0.3.73
3
+ Version: 0.3.74
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-Expression: BSD-2-Clause
@@ -772,7 +772,6 @@ This example shows the flow of control when using inheritance with:
772
772
  - class variable `message_count`
773
773
 
774
774
  ```python
775
- from datetime import datetime
776
775
 
777
776
  class Notification_Service:
778
777
  message_count = 0
@@ -810,14 +809,14 @@ class SMS_Notification(Notification_Service):
810
809
  email = Email_Notification(3, 'support@company.com')
811
810
  email.send('customer@email.com', 'Your report is ready')
812
811
  email.send('customer@email.com', 'Update to Privacy Policy')
813
- sms = Email_Notification(3, '0123456789')
812
+ sms = SMS_Notification(3, '0123456789')
814
813
  sms.send('001122334455', 'Update to Privacy Policy')
815
814
  ```
816
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=36&continues=1&play).
815
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=35&continues=1&play).
817
816
 
818
817
  ## Decorator ##
819
818
 
820
- This example shows the flow of control when using a decorator.
819
+ This example shows the flow of control when using a decorator. A decorator wraps a function and is active before and after the function is called.
821
820
 
822
821
  ```python
823
822
  def log_call(function):
@@ -851,29 +850,135 @@ This example shows the flow of control when using exception handling.
851
850
  def fun2():
852
851
  try:
853
852
  d = [0] * 3
854
- for i in range(4):
853
+ for i in range(6):
855
854
  try:
856
- d[i] = i # raises IndexError when i=3
857
- except TypeError as e:
855
+ print(f'{i=}')
856
+ d[i] = i # raises IndexError when i>=3
857
+ except ZeroDivisionError as e:
858
858
  print(type(e), e)
859
859
  except AssertionError as e:
860
860
  print(type(e), e)
861
-
861
+ print('fun2() returns')
862
+
862
863
  def fun1():
863
864
  try:
864
865
  return fun2()
865
866
  except NameError as e:
866
867
  print(type(e), e)
867
-
868
+ print('fun1() returns')
869
+
868
870
  try:
869
871
  fun1()
870
872
  except LookupError as e:
871
873
  print(type(e), e)
874
+ print('program ended cleanly')
872
875
  ```
873
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=19&continues=1&play). In the program an `IndexError` is raise and matched with various exceptions in the exception hierarchy below. It matches with the 'LookupError' exception and is handled there by just printing it. Exceptions that are not handled stop the execution of a program.
876
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=22&continues=1&play). In the program an `IndexError` exception is raised which propagates up the call stack until it reaches an except clause that matches its type where it is handled. Here, it is handled by the `LookupError` except clause because `IndexError` is a subclass of `LookupError`. Exceptions that are not handled terminate the execution of a program while its traceback is shown for analyses.
874
877
 
875
878
  ![exception_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/exception_tree.png)
876
879
 
880
+ ## Lazy Evaluation ##
881
+
882
+ In the following Eager and Lazy ealuation examples, we use this `pr()` function to print in what order things are created and used.
883
+
884
+ ```python
885
+ def pr(tag, v):
886
+ print(tag, v)
887
+ return v
888
+ ```
889
+
890
+ With eager evaluation, the function creates all three elements up front and stores them in a list before iteration begins. With lazy evaluation, the function returns a generator that creates each element only when it is needed.
891
+
892
+ <table>
893
+ <tr> <td width="50%" valign="top"><strong>Eager</strong></td> <td width="50%" valign="top"><strong>Lazy</strong></td></tr>
894
+ <tr><td width="50%" valign="top">
895
+
896
+ ```python
897
+ def fun():
898
+ result = []
899
+ for i in range(3):
900
+ result.append(pr('create:', i))
901
+ return result
902
+
903
+ for i in fun():
904
+ pr('use:', i)
905
+ ```
906
+
907
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_return.py&play)
908
+
909
+ </td><td width="50%" valign="top">
910
+
911
+ ```python
912
+ def fun():
913
+ for i in range(3):
914
+ yield pr('create:', i)
915
+
916
+
917
+
918
+ for i in fun():
919
+ pr('use:', i)
920
+ ```
921
+
922
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_yield.py&play)
923
+
924
+ </td></tr>
925
+ <tr><td width="50%" valign="top">
926
+
927
+ ```python
928
+ def fun():
929
+ return [
930
+ pr('create:', i)
931
+ for i in range(3)
932
+ ]
933
+
934
+ for i in fun():
935
+ pr('use:', i)
936
+ ```
937
+
938
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_compri.py&play)
939
+
940
+ </td><td width="50%" valign="top">
941
+
942
+ ```python
943
+ def fun():
944
+ return (
945
+ pr('create:', i)
946
+ for i in range(3)
947
+ )
948
+
949
+ for i in fun():
950
+ pr('use:', i)
951
+ ```
952
+
953
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_express.py&play)
954
+
955
+ </td></tr>
956
+ <tr><td width="50%" valign="top">
957
+
958
+ ```text
959
+ create: 0
960
+ create: 1
961
+ create: 2
962
+ use: 0
963
+ use: 1
964
+ use: 2
965
+ ```
966
+
967
+ </td><td width="50%" valign="top">
968
+
969
+ ```text
970
+ create: 0
971
+ use: 0
972
+ create: 1
973
+ use: 1
974
+ create: 2
975
+ use: 2
976
+ ```
977
+
978
+ </td></tr>
979
+ </table>
980
+
981
+
877
982
  # Configuration #
878
983
  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).
879
984
 
@@ -752,7 +752,6 @@ This example shows the flow of control when using inheritance with:
752
752
  - class variable `message_count`
753
753
 
754
754
  ```python
755
- from datetime import datetime
756
755
 
757
756
  class Notification_Service:
758
757
  message_count = 0
@@ -790,14 +789,14 @@ class SMS_Notification(Notification_Service):
790
789
  email = Email_Notification(3, 'support@company.com')
791
790
  email.send('customer@email.com', 'Your report is ready')
792
791
  email.send('customer@email.com', 'Update to Privacy Policy')
793
- sms = Email_Notification(3, '0123456789')
792
+ sms = SMS_Notification(3, '0123456789')
794
793
  sms.send('001122334455', 'Update to Privacy Policy')
795
794
  ```
796
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=36&continues=1&play).
795
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=35&continues=1&play).
797
796
 
798
797
  ## Decorator ##
799
798
 
800
- This example shows the flow of control when using a decorator.
799
+ This example shows the flow of control when using a decorator. A decorator wraps a function and is active before and after the function is called.
801
800
 
802
801
  ```python
803
802
  def log_call(function):
@@ -831,29 +830,135 @@ This example shows the flow of control when using exception handling.
831
830
  def fun2():
832
831
  try:
833
832
  d = [0] * 3
834
- for i in range(4):
833
+ for i in range(6):
835
834
  try:
836
- d[i] = i # raises IndexError when i=3
837
- except TypeError as e:
835
+ print(f'{i=}')
836
+ d[i] = i # raises IndexError when i>=3
837
+ except ZeroDivisionError as e:
838
838
  print(type(e), e)
839
839
  except AssertionError as e:
840
840
  print(type(e), e)
841
-
841
+ print('fun2() returns')
842
+
842
843
  def fun1():
843
844
  try:
844
845
  return fun2()
845
846
  except NameError as e:
846
847
  print(type(e), e)
847
-
848
+ print('fun1() returns')
849
+
848
850
  try:
849
851
  fun1()
850
852
  except LookupError as e:
851
853
  print(type(e), e)
854
+ print('program ended cleanly')
852
855
  ```
853
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=19&continues=1&play). In the program an `IndexError` is raise and matched with various exceptions in the exception hierarchy below. It matches with the 'LookupError' exception and is handled there by just printing it. Exceptions that are not handled stop the execution of a program.
856
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=22&continues=1&play). In the program an `IndexError` exception is raised which propagates up the call stack until it reaches an except clause that matches its type where it is handled. Here, it is handled by the `LookupError` except clause because `IndexError` is a subclass of `LookupError`. Exceptions that are not handled terminate the execution of a program while its traceback is shown for analyses.
854
857
 
855
858
  ![exception_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/exception_tree.png)
856
859
 
860
+ ## Lazy Evaluation ##
861
+
862
+ In the following Eager and Lazy ealuation examples, we use this `pr()` function to print in what order things are created and used.
863
+
864
+ ```python
865
+ def pr(tag, v):
866
+ print(tag, v)
867
+ return v
868
+ ```
869
+
870
+ With eager evaluation, the function creates all three elements up front and stores them in a list before iteration begins. With lazy evaluation, the function returns a generator that creates each element only when it is needed.
871
+
872
+ <table>
873
+ <tr> <td width="50%" valign="top"><strong>Eager</strong></td> <td width="50%" valign="top"><strong>Lazy</strong></td></tr>
874
+ <tr><td width="50%" valign="top">
875
+
876
+ ```python
877
+ def fun():
878
+ result = []
879
+ for i in range(3):
880
+ result.append(pr('create:', i))
881
+ return result
882
+
883
+ for i in fun():
884
+ pr('use:', i)
885
+ ```
886
+
887
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_return.py&play)
888
+
889
+ </td><td width="50%" valign="top">
890
+
891
+ ```python
892
+ def fun():
893
+ for i in range(3):
894
+ yield pr('create:', i)
895
+
896
+
897
+
898
+ for i in fun():
899
+ pr('use:', i)
900
+ ```
901
+
902
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_yield.py&play)
903
+
904
+ </td></tr>
905
+ <tr><td width="50%" valign="top">
906
+
907
+ ```python
908
+ def fun():
909
+ return [
910
+ pr('create:', i)
911
+ for i in range(3)
912
+ ]
913
+
914
+ for i in fun():
915
+ pr('use:', i)
916
+ ```
917
+
918
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_compri.py&play)
919
+
920
+ </td><td width="50%" valign="top">
921
+
922
+ ```python
923
+ def fun():
924
+ return (
925
+ pr('create:', i)
926
+ for i in range(3)
927
+ )
928
+
929
+ for i in fun():
930
+ pr('use:', i)
931
+ ```
932
+
933
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_express.py&play)
934
+
935
+ </td></tr>
936
+ <tr><td width="50%" valign="top">
937
+
938
+ ```text
939
+ create: 0
940
+ create: 1
941
+ create: 2
942
+ use: 0
943
+ use: 1
944
+ use: 2
945
+ ```
946
+
947
+ </td><td width="50%" valign="top">
948
+
949
+ ```text
950
+ create: 0
951
+ use: 0
952
+ create: 1
953
+ use: 1
954
+ create: 2
955
+ use: 2
956
+ ```
957
+
958
+ </td></tr>
959
+ </table>
960
+
961
+
857
962
  # Configuration #
858
963
  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).
859
964
 
@@ -2,7 +2,7 @@
2
2
  # Copyright (c) 2023, Bas Terwijn.
3
3
  # SPDX-License-Identifier: BSD-2-Clause
4
4
 
5
- __version__ = "0.3.73"
5
+ __version__ = "0.3.74"
6
6
  __author__ = 'Bas Terwijn'
7
7
 
8
8
  import memory_graph.memory_to_nodes as memory_to_nodes
@@ -29,10 +29,13 @@ type_to_string = { }
29
29
 
30
30
  def to_string(data):
31
31
  """ Convert data to string. """
32
- data_type = type(data)
33
- if data_type in type_to_string:
34
- return type_to_string[data_type](data)
35
- return str(data)
32
+ try:
33
+ data_type = type(data)
34
+ if data_type in type_to_string:
35
+ return type_to_string[data_type](data)
36
+ return str(data)
37
+ except Exception as e:
38
+ return f'no stringification, {type(e).__name__}: {e}'
36
39
 
37
40
  type_to_node = { }
38
41
 
@@ -15,6 +15,7 @@ def get_dict_attributes(value):
15
15
  return getattr(value,"__dict__")
16
16
 
17
17
  def is_not_state(obj):
18
+ """ Returns 'True' if 'obj' is not considered state, e.g. a function or method. """
18
19
  if isinstance(obj, (types.FunctionType, types.MethodType,
19
20
  types.BuiltinFunctionType, types.BuiltinMethodType,
20
21
  classmethod, staticmethod,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memory_graph
3
- Version: 0.3.73
3
+ Version: 0.3.74
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-Expression: BSD-2-Clause
@@ -772,7 +772,6 @@ This example shows the flow of control when using inheritance with:
772
772
  - class variable `message_count`
773
773
 
774
774
  ```python
775
- from datetime import datetime
776
775
 
777
776
  class Notification_Service:
778
777
  message_count = 0
@@ -810,14 +809,14 @@ class SMS_Notification(Notification_Service):
810
809
  email = Email_Notification(3, 'support@company.com')
811
810
  email.send('customer@email.com', 'Your report is ready')
812
811
  email.send('customer@email.com', 'Update to Privacy Policy')
813
- sms = Email_Notification(3, '0123456789')
812
+ sms = SMS_Notification(3, '0123456789')
814
813
  sms.send('001122334455', 'Update to Privacy Policy')
815
814
  ```
816
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=36&continues=1&play).
815
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=35&continues=1&play).
817
816
 
818
817
  ## Decorator ##
819
818
 
820
- This example shows the flow of control when using a decorator.
819
+ This example shows the flow of control when using a decorator. A decorator wraps a function and is active before and after the function is called.
821
820
 
822
821
  ```python
823
822
  def log_call(function):
@@ -851,29 +850,135 @@ This example shows the flow of control when using exception handling.
851
850
  def fun2():
852
851
  try:
853
852
  d = [0] * 3
854
- for i in range(4):
853
+ for i in range(6):
855
854
  try:
856
- d[i] = i # raises IndexError when i=3
857
- except TypeError as e:
855
+ print(f'{i=}')
856
+ d[i] = i # raises IndexError when i>=3
857
+ except ZeroDivisionError as e:
858
858
  print(type(e), e)
859
859
  except AssertionError as e:
860
860
  print(type(e), e)
861
-
861
+ print('fun2() returns')
862
+
862
863
  def fun1():
863
864
  try:
864
865
  return fun2()
865
866
  except NameError as e:
866
867
  print(type(e), e)
867
-
868
+ print('fun1() returns')
869
+
868
870
  try:
869
871
  fun1()
870
872
  except LookupError as e:
871
873
  print(type(e), e)
874
+ print('program ended cleanly')
872
875
  ```
873
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=19&continues=1&play). In the program an `IndexError` is raise and matched with various exceptions in the exception hierarchy below. It matches with the 'LookupError' exception and is handled there by just printing it. Exceptions that are not handled stop the execution of a program.
876
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=22&continues=1&play). In the program an `IndexError` exception is raised which propagates up the call stack until it reaches an except clause that matches its type where it is handled. Here, it is handled by the `LookupError` except clause because `IndexError` is a subclass of `LookupError`. Exceptions that are not handled terminate the execution of a program while its traceback is shown for analyses.
874
877
 
875
878
  ![exception_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/exception_tree.png)
876
879
 
880
+ ## Lazy Evaluation ##
881
+
882
+ In the following Eager and Lazy ealuation examples, we use this `pr()` function to print in what order things are created and used.
883
+
884
+ ```python
885
+ def pr(tag, v):
886
+ print(tag, v)
887
+ return v
888
+ ```
889
+
890
+ With eager evaluation, the function creates all three elements up front and stores them in a list before iteration begins. With lazy evaluation, the function returns a generator that creates each element only when it is needed.
891
+
892
+ <table>
893
+ <tr> <td width="50%" valign="top"><strong>Eager</strong></td> <td width="50%" valign="top"><strong>Lazy</strong></td></tr>
894
+ <tr><td width="50%" valign="top">
895
+
896
+ ```python
897
+ def fun():
898
+ result = []
899
+ for i in range(3):
900
+ result.append(pr('create:', i))
901
+ return result
902
+
903
+ for i in fun():
904
+ pr('use:', i)
905
+ ```
906
+
907
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_return.py&play)
908
+
909
+ </td><td width="50%" valign="top">
910
+
911
+ ```python
912
+ def fun():
913
+ for i in range(3):
914
+ yield pr('create:', i)
915
+
916
+
917
+
918
+ for i in fun():
919
+ pr('use:', i)
920
+ ```
921
+
922
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_yield.py&play)
923
+
924
+ </td></tr>
925
+ <tr><td width="50%" valign="top">
926
+
927
+ ```python
928
+ def fun():
929
+ return [
930
+ pr('create:', i)
931
+ for i in range(3)
932
+ ]
933
+
934
+ for i in fun():
935
+ pr('use:', i)
936
+ ```
937
+
938
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_compri.py&play)
939
+
940
+ </td><td width="50%" valign="top">
941
+
942
+ ```python
943
+ def fun():
944
+ return (
945
+ pr('create:', i)
946
+ for i in range(3)
947
+ )
948
+
949
+ for i in fun():
950
+ pr('use:', i)
951
+ ```
952
+
953
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_express.py&play)
954
+
955
+ </td></tr>
956
+ <tr><td width="50%" valign="top">
957
+
958
+ ```text
959
+ create: 0
960
+ create: 1
961
+ create: 2
962
+ use: 0
963
+ use: 1
964
+ use: 2
965
+ ```
966
+
967
+ </td><td width="50%" valign="top">
968
+
969
+ ```text
970
+ create: 0
971
+ use: 0
972
+ create: 1
973
+ use: 1
974
+ create: 2
975
+ use: 2
976
+ ```
977
+
978
+ </td></tr>
979
+ </table>
980
+
981
+
877
982
  # Configuration #
878
983
  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).
879
984
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "memory_graph"
7
- version = "0.3.73"
7
+ version = "0.3.74"
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