Skip to content

Commit a3407dd

Browse files
Fix flyweight_with_metaclass sharing instances for different arguments (#495)
The pool key concatenated str(arg) with no separator, so Card2('1', '0') and Card2('10') (or Card2(1) and Card2('1')) got the same key and the second call returned the first call's instance. Use repr of the class name, args and sorted kwargs instead, which also makes the key independent of kwarg order. Add tests, since the module had none. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 00fcfc4 commit a3407dd

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

‎patterns/structural/flyweight_with_metaclass.py‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,11 @@ def __new__(mcs, name, parents, dct):
1919
def _serialize_params(cls, *args, **kwargs):
2020
"""
2121
Serialize input parameters to a key.
22-
Simple implementation is just to serialize it as a string
22+
Simple implementation is just to serialize it as a string. ``repr`` keeps
23+
``("1", "0")``, ``("10",)`` and ``(1,)`` apart, and sorting the keyword
24+
arguments makes the key independent of their order.
2325
"""
24-
args_list = list(map(str, args))
25-
args_list.extend([str(kwargs), cls.__name__])
26-
key = "".join(args_list)
27-
return key
26+
return repr((cls.__name__, args, sorted(kwargs.items())))
2827

2928
def __call__(cls, *args, **kwargs):
3029
key = FlyweightMeta._serialize_params(cls, *args, **kwargs)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from patterns.structural.flyweight_with_metaclass import Card2
2+
3+
4+
def test_same_arguments_share_an_instance():
5+
Card2.pool.clear()
6+
assert Card2("10", "h", a=1) is Card2("10", "h", a=1)
7+
8+
9+
def test_different_arguments_do_not_share_an_instance():
10+
Card2.pool.clear()
11+
assert Card2("10", "h", a=1) is not Card2("10", "h", a=2)
12+
13+
14+
def test_argument_boundaries_are_part_of_the_key():
15+
Card2.pool.clear()
16+
assert Card2("1", "0") is not Card2("10")
17+
18+
19+
def test_argument_types_are_part_of_the_key():
20+
Card2.pool.clear()
21+
assert Card2(1) is not Card2("1")
22+
23+
24+
def test_keyword_argument_order_does_not_matter():
25+
Card2.pool.clear()
26+
assert Card2(a=1, b=2) is Card2(b=2, a=1)

0 commit comments

Comments
 (0)