From 0a4e05a7f4ab50bffc862b5cac33d7c0d11e0092 Mon Sep 17 00:00:00 2001 From: Darkslayer3324j Date: Sun, 20 Sep 2026 02:11:15 +0500 Subject: [PATCH] Fix flyweight_with_metaclass sharing instances for different arguments 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 --- .../structural/flyweight_with_metaclass.py | 9 +++---- .../test_flyweight_with_metaclass.py | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/structural/test_flyweight_with_metaclass.py diff --git a/patterns/structural/flyweight_with_metaclass.py b/patterns/structural/flyweight_with_metaclass.py index ced8d9159..798442344 100644 --- a/patterns/structural/flyweight_with_metaclass.py +++ b/patterns/structural/flyweight_with_metaclass.py @@ -19,12 +19,11 @@ def __new__(mcs, name, parents, dct): def _serialize_params(cls, *args, **kwargs): """ Serialize input parameters to a key. - Simple implementation is just to serialize it as a string + Simple implementation is just to serialize it as a string. ``repr`` keeps + ``("1", "0")``, ``("10",)`` and ``(1,)`` apart, and sorting the keyword + arguments makes the key independent of their order. """ - args_list = list(map(str, args)) - args_list.extend([str(kwargs), cls.__name__]) - key = "".join(args_list) - return key + return repr((cls.__name__, args, sorted(kwargs.items()))) def __call__(cls, *args, **kwargs): key = FlyweightMeta._serialize_params(cls, *args, **kwargs) diff --git a/tests/structural/test_flyweight_with_metaclass.py b/tests/structural/test_flyweight_with_metaclass.py new file mode 100644 index 000000000..5a3421822 --- /dev/null +++ b/tests/structural/test_flyweight_with_metaclass.py @@ -0,0 +1,26 @@ +from patterns.structural.flyweight_with_metaclass import Card2 + + +def test_same_arguments_share_an_instance(): + Card2.pool.clear() + assert Card2("10", "h", a=1) is Card2("10", "h", a=1) + + +def test_different_arguments_do_not_share_an_instance(): + Card2.pool.clear() + assert Card2("10", "h", a=1) is not Card2("10", "h", a=2) + + +def test_argument_boundaries_are_part_of_the_key(): + Card2.pool.clear() + assert Card2("1", "0") is not Card2("10") + + +def test_argument_types_are_part_of_the_key(): + Card2.pool.clear() + assert Card2(1) is not Card2("1") + + +def test_keyword_argument_order_does_not_matter(): + Card2.pool.clear() + assert Card2(a=1, b=2) is Card2(b=2, a=1)