0

I am wanting to understand how Python maintains its reference to the array value between the first call and second call to the function. Is there a symbolic table that can be queried or looked at to see what the object values are between the first and second call.

def scopeUnderstanding2(a, myArray=[]):
    print(f"myArray in func scopeUnderstanding2 myArray : {myArray}")
    myArray.append(a)
    print(f"myArray in func after .append(a) myArray : {myArray}")

print (scopeUnderstanding2(1)) 
print (scopeUnderstanding2(2)) 

myArray in func scopeUnderstanding2 myArray : []
myArray in func after .append(a) myArray : [1]
None
myArray in func scopeUnderstanding2 myArray : [1]
myArray in func after .append(a) myArray : [1, 2]
None
  • The default parameter values, which were evaluated at the time the function was defined, are kept in the `__defaults__` attribute of the function itself (`func_defaults` in older versions). Note that it's generally considered a mistake to use a mutable value as a default, as the results can be quite unexpected. – jasonharper Jul 06 '23 at 14:37

1 Answers1

1

Any default parameters that you define in the function's def statement are stored as part of the resulting function object in an attribute called __defaults__:

>>> def scopeUnderstanding2(a, myArray=[]):
...     print(f"myArray in func scopeUnderstanding2 myArray : {myArray}")
...     myArray.append(a)
...     print(f"myArray in func after .append(a) myArray : {myArray}")
...
>>> dir(scopeUnderstanding2)
['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> scopeUnderstanding2.__defaults__
([],)
>>> scopeUnderstanding2(1)
myArray in func scopeUnderstanding2 myArray : []
myArray in func after .append(a) myArray : [1]
>>> scopeUnderstanding2.__defaults__
([1],)

If myArray had been declared as a local variable inside the body of the function, it would be re-created each time the function is called, rather than associated permanently with the function object itself.

Samwise
  • 68,105
  • 3
  • 30
  • 44
  • It might be important adding there that most uses of mutable objects as default parameters are made by people _unaware_ that the same object will be used across calls, and it is one of the major "gotchas" in Python. – jsbueno Jul 06 '23 at 14:32
  • And to your point in the last paragraph - that's why we have the idiom of making the default parameter `myArray=None`, and then at the start of the function doing `myArray = myArray or []` or similar. – slothrop Jul 06 '23 at 14:51
  • OP's question strongly implies to me that they're already aware of how it works, and are just curious about where exactly the default parameter lives and how to peek at it. :) But anyone who's actually being bitten by this behavior or trying to understand *why* it works this way should check out https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument – Samwise Jul 06 '23 at 15:30