From b7d5be18aa7e929c6ec7a534118c54e3f15fa771 Mon Sep 17 00:00:00 2001 From: Mr-Neutr0n <64578610+Mr-Neutr0n@users.noreply.github.com> Date: Thu, 12 Feb 2026 00:15:00 +0530 Subject: [PATCH] Fix mutable default argument in __deepcopy__ methods Replace `memodict={}` with `memodict=None` and add a guard clause to initialize to `{}` inside the method body. Mutable default arguments are shared across all calls to the function, which can lead to subtle bugs (see https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments). Affected files: - merlion/utils/conj_priors.py - merlion/post_process/base.py - merlion/models/base.py (2 instances) - merlion/models/layers.py - merlion/models/ensemble/base.py - merlion/models/ensemble/combine.py --- merlion/models/base.py | 8 ++++++-- merlion/models/ensemble/base.py | 4 +++- merlion/models/ensemble/combine.py | 4 +++- merlion/models/layers.py | 4 +++- merlion/post_process/base.py | 4 +++- merlion/utils/conj_priors.py | 4 +++- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/merlion/models/base.py b/merlion/models/base.py index 1cf7f3aea..e8e3cbe4b 100644 --- a/merlion/models/base.py +++ b/merlion/models/base.py @@ -103,7 +103,9 @@ def __reduce__(self): def __copy__(self): return self.from_dict(self.to_dict()) - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict=None): + if memodict is None: + memodict = {} return self.__copy__() def get_unused_kwargs(self, **kwargs): @@ -467,7 +469,9 @@ def __copy__(self): new_model.__setstate__(state_dict) return new_model - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict=None): + if memodict is None: + memodict = {} new_model = self.__class__(config=copy.deepcopy(self.config)) state_dict = self.__getstate__() state_dict.pop("config", None) diff --git a/merlion/models/ensemble/base.py b/merlion/models/ensemble/base.py index cb17bed95..04df643e2 100644 --- a/merlion/models/ensemble/base.py +++ b/merlion/models/ensemble/base.py @@ -71,7 +71,9 @@ def __copy__(self): config_dict["models"] = self.models return self.from_dict(config_dict) - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict=None): + if memodict is None: + memodict = {} copied = copy.copy(self) copied.models = copy.deepcopy(self.models) return copied diff --git a/merlion/models/ensemble/combine.py b/merlion/models/ensemble/combine.py index 0dd4d1956..799785fdf 100644 --- a/merlion/models/ensemble/combine.py +++ b/merlion/models/ensemble/combine.py @@ -83,7 +83,9 @@ def from_dict(cls, state): def __copy__(self): return self.from_dict(self.to_dict()) - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict=None): + if memodict is None: + memodict = {} return self.__copy__() @abstractmethod diff --git a/merlion/models/layers.py b/merlion/models/layers.py index d3f769658..f148b61e3 100644 --- a/merlion/models/layers.py +++ b/merlion/models/layers.py @@ -129,7 +129,9 @@ def __copy__(self): config_dict["model"] = self.model return self.from_dict(config_dict) - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict=None): + if memodict is None: + memodict = {} config_dict = super().to_dict(_skipped_keys={"model"}) config_dict["model"] = copy.deepcopy(self.model) return self.from_dict(config_dict) diff --git a/merlion/post_process/base.py b/merlion/post_process/base.py index 14d21ec2d..a1dcc3762 100644 --- a/merlion/post_process/base.py +++ b/merlion/post_process/base.py @@ -38,7 +38,9 @@ def from_dict(cls, state_dict): def __copy__(self): return self.from_dict(self.to_dict()) - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict=None): + if memodict is None: + memodict = {} return self.__copy__() def __repr__(self): diff --git a/merlion/utils/conj_priors.py b/merlion/utils/conj_priors.py index a73b8f0a6..a44ec4c3a 100644 --- a/merlion/utils/conj_priors.py +++ b/merlion/utils/conj_priors.py @@ -88,7 +88,9 @@ def __copy__(self): setattr(ret, k, copy.deepcopy(v)) return ret - def __deepcopy__(self, memodict={}): + def __deepcopy__(self, memodict=None): + if memodict is None: + memodict = {} return self.__copy__() @staticmethod