{"id":2195,"date":"2025-09-05T10:13:48","date_gmt":"2025-09-05T10:13:48","guid":{"rendered":"https:\/\/www.cmarix.com\/qanda\/?p=2195"},"modified":"2026-02-05T11:59:26","modified_gmt":"2026-02-05T11:59:26","slug":"python-list-changing-function-calls-class-instances","status":"publish","type":"post","link":"https:\/\/www.cmarix.com\/qanda\/python-list-changing-function-calls-class-instances\/","title":{"rendered":"Why is My Python List Unexpectedly Changing Across Function Calls or Class Instances?"},"content":{"rendered":"\n<p>If you&#8217;ve ever seen a list or dictionary mysteriously change between function calls or across different instances of a class, you&#8217;re not alone. This behavior usually stems from using mutable default arguments, a classic Python gotcha. Let\u2019s look at what causes it and how to avoid it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Description of the Problem<\/h2>\n\n\n\n<p>You might encounter a strange situation where a list (or dictionary) you define as a default argument in a function or a class is changing unexpectedly across calls or object instances.<\/p>\n\n\n\n<p><strong>For example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def add_item(item, collection=&#91;]):\n    collection.append(item)\n    return collection\n\nprint(add_item(\"apple\"))     # &#91;'apple']\nprint(add_item(\"banana\"))    # &#91;'apple', 'banana'] \u2190 Unexpected?<\/code><\/pre>\n\n\n\n<p><strong>Or in a class:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Cart:\n    def __init__(self, items=&#91;]):\n        self.items = items\n\ncart1 = Cart()\ncart1.items.append(\"apple\")\n\ncart2 = Cart()\nprint(cart2.items)  # &#91;'apple'] \u2190 Wait, what?<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Why This Happens<\/h2>\n\n\n\n<p>This behavior is due to a common Python pitfall involving mutable default arguments. In Python, default argument values are evaluated only once at the time the function or class is defined, not each time it\u2019s called.<\/p>\n\n\n\n<p>So when you define collection=[], that same list object is reused in every function call or class instance unless explicitly overridden. This leads to shared state and subtle bugs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Steps to Resolve the Issue<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Use None as the Default Argument and Create Inside the Function<\/h3>\n\n\n\n<p>This is the standard workaround in Python:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def add_item(item, collection=None):\n    if collection is None:\n        collection = &#91;]\n    collection.append(item)\n    return collection<\/code><\/pre>\n\n\n\n<p>Each call now gets its own list, avoiding shared state:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>print(add_item(\"apple\"))    # &#91;'apple']\nprint(add_item(\"banana\"))   # &#91;'banana']<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Apply the Same Principle in Class Constructors<\/h3>\n\n\n\n<p><strong>Fixing the class example:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Cart:\n    def __init__(self, items=None):\n        if items is None:\n            items = &#91;]\n        self.items = items<\/code><\/pre>\n\n\n\n<p>Now each instance of Cart has its own independent list.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Be Careful with All Mutable Defaults<\/h3>\n\n\n\n<p>This issue also applies to dictionaries, sets, or custom objects.<\/p>\n\n\n\n<p><strong>Bad:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def config(settings={}):  # Shared across calls!<\/code><\/pre>\n\n\n\n<p><strong>Good:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def config(settings=None):\n    if settings is None:\n        settings = {}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Quick Recap<\/h2>\n\n\n\n<p>In Python, default mutable arguments (like lists or dicts) are shared across calls because they are evaluated only once at definition time. This can lead to bugs that are hard to track, especially in larger codebases or shared modules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Best Practices:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Never use mutable objects as default arguments<\/li>\n\n\n\n<li>Use None and create a new object inside the function or constructor<\/li>\n\n\n\n<li>Review any third-party code or libraries that might use mutable defaults, it&#8217;s a common gotcha even among experienced developers<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Using mutable default arguments in Python can cause unexpected behavior, especially in larger applications where function calls and class instances stack up. To avoid these hard-to-spot bugs, it\u2019s best to follow safe patterns or better, <a href=\"https:\/\/www.cmarix.com\/hire-python-developers.html\">hire Python developers<\/a> who already know how to structure code defensively and cleanly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;ve ever seen a list or dictionary mysteriously change between function calls or across different instances of a class, you&#8217;re not alone. This behavior usually stems from using mutable default arguments, a classic Python gotcha. Let\u2019s look at what causes it and how to avoid it. Description of the Problem You might encounter a [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":2199,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[163,3],"tags":[],"class_list":["post-2195","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python","category-web"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/comments?post=2195"}],"version-history":[{"count":4,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2195\/revisions"}],"predecessor-version":[{"id":2201,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/posts\/2195\/revisions\/2201"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media\/2199"}],"wp:attachment":[{"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/media?parent=2195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/categories?post=2195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmarix.com\/qanda\/wp-json\/wp\/v2\/tags?post=2195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}