Skip to content

Commit 20fd678

Browse files
author
root
committed
update examples
1 parent ae22e94 commit 20fd678

File tree

6 files changed

+153
-0
lines changed

6 files changed

+153
-0
lines changed

examples/bounded_wrapped_ints.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
from weakref import WeakValueDictionary
2+
3+
import pytest
4+
5+
from newtype import NewType
6+
7+
8+
class GenericWrappedBoundedInt_WithNewType(NewType(int)): # never mind about the '_'
9+
MAX_VALUE: int = 0
10+
11+
__CONCRETE_BOUNDED_INTS__ = WeakValueDictionary()
12+
13+
def __new__(self, value: int):
14+
inst = super().__new__(self, value % self.MAX_VALUE)
15+
return inst
16+
17+
def __repr__(self) -> str:
18+
return f"<BoundedInt[MAX_VALUE={self.MAX_VALUE}]: {super().__repr__()}>"
19+
20+
def __str__(self) -> str:
21+
return repr(self)
22+
23+
def __class_getitem__(cls, idx=MAX_VALUE):
24+
if not isinstance(idx, int):
25+
raise TypeError(f"cannot make `BoundedInt[{idx}]`")
26+
27+
if idx not in cls.__CONCRETE_BOUNDED_INTS__:
28+
29+
class ConcreteBoundedInt(cls):
30+
MAX_VALUE = idx
31+
32+
cls.__CONCRETE_BOUNDED_INTS__[idx] = ConcreteBoundedInt
33+
34+
return cls.__CONCRETE_BOUNDED_INTS__[idx]
35+
36+
# here you have NO need to write many operator overrides: +, -, etc.
37+
38+
39+
class GenericWrappedBoundedInt_WithoutNewType(int): # never mind about the '_'
40+
MAX_VALUE: int = 0
41+
42+
__CONCRETE_BOUNDED_INTS__ = WeakValueDictionary()
43+
44+
def __new__(self, value: int):
45+
inst = super().__new__(self, value % self.MAX_VALUE)
46+
return inst
47+
48+
def __repr__(self) -> str:
49+
return f"<BoundedInt[MAX_VALUE={self.MAX_VALUE}]: {super().__repr__()}>"
50+
51+
def __str__(self) -> str:
52+
return repr(self)
53+
54+
def __class_getitem__(cls, idx=MAX_VALUE):
55+
if not isinstance(idx, int):
56+
raise TypeError(f"cannot make `BoundedInt[{idx}]`")
57+
58+
if idx not in cls.__CONCRETE_BOUNDED_INTS__:
59+
60+
class ConcreteBoundedInt(cls):
61+
MAX_VALUE = idx
62+
63+
cls.__CONCRETE_BOUNDED_INTS__[idx] = ConcreteBoundedInt
64+
65+
return cls.__CONCRETE_BOUNDED_INTS__[idx]
66+
67+
def __mul__(
68+
self, other: "GenericWrappedBoundedInt_WithoutNewType"
69+
) -> "GenericWrappedBoundedInt_WithoutNewType":
70+
# handwritten `__mul__`
71+
return self.__class__(int(self) * int(other))
72+
73+
# here you got to write many operator overrides: +, -, etc.
74+
75+
76+
def test_bounded_int_without_newtype():
77+
# pytest examples/bounded_wrapped_ints.py -s -vv
78+
bounded_twenty_int_value = GenericWrappedBoundedInt_WithoutNewType[20](11)
79+
80+
bounded_twenty_int_value += 10 # return type here is int
81+
with pytest.raises(AssertionError):
82+
# (11 + 10 = 21) % 20 = 1
83+
assert bounded_twenty_int_value == (11 + 10) % 20
84+
# but no: `bounded_twenty_int_value` = 11 + 10 = 21
85+
assert bounded_twenty_int_value == 21 #
86+
assert isinstance(bounded_twenty_int_value, int)
87+
assert not isinstance(bounded_twenty_int_value, GenericWrappedBoundedInt_WithoutNewType[20])
88+
89+
bounded_twenty_int_value -= 22
90+
with pytest.raises(AssertionError):
91+
# (21 - 22 = -1) % 20 = 19
92+
assert bounded_twenty_int_value == (21 - 22) % 20
93+
# but no: `bounded_twenty_int_value` = 21 - 22 = -1
94+
assert bounded_twenty_int_value == -1
95+
assert isinstance(bounded_twenty_int_value, int)
96+
assert not isinstance(bounded_twenty_int_value, GenericWrappedBoundedInt_WithoutNewType[20])
97+
98+
99+
def test_bounded_int_with_newtype():
100+
# pytest examples/bounded_wrapped_ints.py -s -vv
101+
bounded_twenty_int_value = GenericWrappedBoundedInt_WithNewType[20](11)
102+
103+
bounded_twenty_int_value += 10
104+
assert bounded_twenty_int_value == (11 + 10) % 20 # (11 + 10 = 21) % 20 = 1
105+
assert isinstance(bounded_twenty_int_value, GenericWrappedBoundedInt_WithNewType[20])
106+
107+
another_bounded_twenty_int_value = GenericWrappedBoundedInt_WithNewType[20](11)
108+
yet_another_bounded_twenty_int_value = another_bounded_twenty_int_value + 10
109+
assert yet_another_bounded_twenty_int_value == (11 + 10) % 20 # (11 + 10 = 21) % 20 = 1
110+
assert isinstance(
111+
yet_another_bounded_twenty_int_value, GenericWrappedBoundedInt_WithNewType[20]
112+
)
113+
114+
bounded_twenty_int_value -= 21
115+
assert bounded_twenty_int_value == (1 - 21) % 20 # (1 - 21 = -20) % 20 = 0
116+
assert isinstance(bounded_twenty_int_value, GenericWrappedBoundedInt_WithNewType[20])
117+
118+
119+
def benchmark():
120+
# python -m examples.bounded_wrapped_ints
121+
import time
122+
123+
bounded_twenty_int_value_wo_newtype = GenericWrappedBoundedInt_WithoutNewType[20](11)
124+
bounded_twenty_int_value_w_newtype = GenericWrappedBoundedInt_WithNewType[20](11)
125+
126+
start_time = time.time()
127+
for _ in range(100_000):
128+
bounded_twenty_int_value_wo_newtype *= 10
129+
end_time = time.time()
130+
print(f"Benchmark completed in {end_time - start_time:.10f} seconds")
131+
print(f"Final value: {bounded_twenty_int_value_wo_newtype}")
132+
assert bounded_twenty_int_value_wo_newtype == (11 * 10 * 100_000) % 20
133+
134+
start_time = time.time()
135+
for _ in range(100_000):
136+
bounded_twenty_int_value_w_newtype *= 10
137+
end_time = time.time()
138+
print(f"Benchmark completed in {end_time - start_time:.10f} seconds")
139+
print(f"Final value: {bounded_twenty_int_value_w_newtype}")
140+
assert bounded_twenty_int_value_w_newtype == (11 * 10 * 100_000) % 20
141+
142+
# `bounded_twenty_int_value_wo_newtype`
143+
# Benchmark completed in 0.1382505894 seconds
144+
# Final value: <BoundedInt[MAX_VALUE=20]: 0>
145+
146+
# `bounded_twenty_int_value_w_newtype`
147+
# Benchmark completed in 0.5179963112 seconds
148+
# Final value: <BoundedInt[MAX_VALUE=20]: 0>
149+
150+
151+
if __name__ == "__main__":
152+
benchmark()

examples/bwint_1.png

87.1 KB
Loading

examples/bwint_2.png

90 KB
Loading

examples/bwint_3.png

81.4 KB
Loading

examples/bwint_4.png

58.9 KB
Loading

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ exclude = [
139139
"scripts/",
140140
"tests/",
141141
"examples/email_str.py",
142+
"examples/bounded_wrapped_ints.py",
142143
]
143144

144145
[tool.ruff.format]

0 commit comments

Comments
 (0)