Python optional parameters

31,404

Solution 1

You need to understand how default values work in order to use them effectively.

Functions are objects. As such, they have attributes. So, if I create this function:

>>> def f(x, y=[]):
        y.append(x)
        return y

I've created an object. Here are its attributes:

>>> dir(f)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',   
'__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',    
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 
'func_name']

One of them is func_defaults. That sounds promising, what's in there?

>>> f.func_defaults
([],)

That's a tuple that contains the function's default values. If a default value is an object, the tuple contains an instance of that object.

This leads to some fairly counterintuitive behavior if you're thinking that f adds an item to a list, returning a list containing only that item if no list is provided:

>>> f(1)
[1]
>>> f(2)
[1, 2]

But if you know that the default value is an object instance that's stored in one of the function's attributes, it's much less counterintuitive:

>>> x = f(3)
>>> y = f(4)
>>> x == y
True
>>> x
[1, 2, 3, 4]
>>> x.append(5)
>>> f(6)
[1, 2, 3, 4, 5, 6]

Knowing this, it's clear that if you want a default value of a function's parameter to be a new list (or any new object), you can't simply stash an instance of the object in func_defaults. You have to create a new one every time the function is called:

>>>def g(x, y=None):
       if y==None:
           y = []
       y.append(x)
       return y

Solution 2

you need to do the following:

class A:
    def __init__(self, builds=None):
        if builds is None:
            builds = B()
        self.builds = builds

it's a very wide-spread error, using mutable parameters as a default arguments. there are plenty of dupes probably on SO.

Solution 3

Yes; default parameters are evaluated only at the time when the function is defined.

One possible solution would be to have the parameter be a class rather than an instance, a la

def foo(blah, klass = B):
    b = klass()
    # etc
Share:
31,404
user192048
Author by

user192048

Updated on August 05, 2022

Comments

  • user192048
    user192048 almost 2 years

    Guys, I just started python recently and get confused with the optional parameters, say I have the program like this:

    class B:
       pass
    
    class A:
        def __init__(self, builds = B()):
            self.builds = builds
    

    If I create A twice

    b = A()
    c = A()
    

    and print their builds

    print b.builds
    print c.builds
    

    I found they are using the exactly same object,

    <__main__.B instance at 0x68ee0>
    <__main__.B instance at 0x68ee0>
    

    But it is not what I want, since if b changed some internal state of builds, the one in c object will also be changed.

    Is it possible to recreate this optional parameters each time by using this optional parameters syntax?