Skip to content

Commit d8b91cf

Browse files
committed
Add example of type hints for classes
1 parent 5345728 commit d8b91cf

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

source-code/typing/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ Type checking can be done using [mypy](http://mypy-lang.org/index.html).
4242
1. `classes.py`: illustration of using type hints with a user-defined class.
4343
1. `classes_incorrect.py`: illustration of using type hints with a user-defined
4444
class with errors.
45+
1. `tree.py`: illustration of using type hints on more sophisticated classes.

source-code/typing/tree.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env python
2+
3+
import textwrap
4+
from typing import Any, Callable, Self
5+
6+
7+
type TransformFunc = Callable[[Node], None]
8+
type VisitFunc = Callable[[Node], Any]
9+
type AggrFunc = Callable[[Any, Any, Any], Any]
10+
11+
12+
class Node:
13+
_left: Self | None
14+
_right: Self | None
15+
_data: int
16+
17+
def __init__(self, data: int):
18+
self._left = None
19+
self._right = None
20+
self._data = data
21+
22+
@property
23+
def left(self) -> Self | None:
24+
return self._left
25+
26+
@left.setter
27+
def left(self, left: Self) -> None:
28+
self._left = left
29+
30+
@property
31+
def right(self) -> Self | None:
32+
return self._right
33+
34+
@right.setter
35+
def right(self, right: Self) -> None:
36+
self._right = right
37+
38+
@property
39+
def data(self) -> int:
40+
return self._data
41+
42+
@data.setter
43+
def data(self, data: int) -> None:
44+
self._data = data
45+
46+
@property
47+
def is_leaf(self) -> bool:
48+
return not (self.has_left or self.has_right)
49+
50+
@property
51+
def has_left(self) -> bool:
52+
return self._left is not None
53+
54+
@property
55+
def has_right(self) -> bool:
56+
return self._right is not None
57+
58+
@property
59+
def nr_descendants(self) -> int:
60+
count = 0
61+
if self._left is not None:
62+
count += 1 + self._left.nr_descendants
63+
if self._right is not None:
64+
count += 1 + self._right.nr_descendants
65+
return count
66+
67+
def transformn(self, func: TransformFunc) -> None:
68+
func(self)
69+
if self._left is not None:
70+
self._left.transformn(func)
71+
if self._right is not None:
72+
self._right.transformn(func)
73+
74+
def __str__(self) -> str:
75+
return f"{self.data}"
76+
77+
def __repr__(self) -> str:
78+
return f"{self.data}"
79+
80+
def visit(self, visit_func: VisitFunc, aggr_func: AggrFunc) -> Any:
81+
self_value = visit_func(self)
82+
left_value = (
83+
self._left.visit(visit_func, aggr_func) if self._left is not None else None
84+
)
85+
right_value = (
86+
self._right.visit(visit_func, aggr_func)
87+
if self._right is not None
88+
else None
89+
)
90+
return aggr_func(self_value, left_value, right_value)
91+
92+
93+
def str_visit(node: Node) -> str:
94+
return str(node.data)
95+
96+
97+
def str_aggr(self_value: str, left_value: str, right_value: str) -> str:
98+
indent = " "
99+
aggr = self_value
100+
if left_value is not None:
101+
aggr += "\n" + textwrap.indent(left_value, indent)
102+
if right_value is not None:
103+
aggr += "\n" + textwrap.indent(right_value, indent)
104+
return aggr
105+
106+
107+
def double_value(node: Node) -> None:
108+
node.data = 2 * node.data
109+
110+
111+
class Tree:
112+
_root: Node | None
113+
114+
def __init__(self, root: Node | None = None):
115+
self._root = root
116+
117+
@property
118+
def root(self) -> Node | None:
119+
return self._root
120+
121+
@root.setter
122+
def root(self, root: Node) -> None:
123+
self._root = root
124+
125+
@property
126+
def nr_of_nodes(self) -> int:
127+
return 0 if self._root is None else 1 + self._root.nr_descendants
128+
129+
def transformn(self, func: TransformFunc) -> None:
130+
if self._root is not None:
131+
self._root.transformn(func)
132+
133+
def __str__(self) -> str:
134+
return "" if self._root is None else self._root.visit(str_visit, str_aggr)
135+
136+
def __repr__(self) -> str:
137+
return f"{self._root}"
138+
139+
140+
if __name__ == "__main__":
141+
root = Node(1)
142+
root.left = Node(2)
143+
root.right = Node(3)
144+
root.left.left = Node(4)
145+
root.left.right = Node(5)
146+
root.right.left = Node(6)
147+
root.right.right = Node(7)
148+
tree = Tree(root)
149+
print(tree)
150+
print(f"number of nodes = {tree.nr_of_nodes}")
151+
tree.transformn(double_value)
152+
print(tree)

0 commit comments

Comments
 (0)