3

Say we have a function in a file, something like:

..... other fucntions
def add_to_list(l = []):
    l.append("foo")
..... other functions

When will def be called? What exactly does def do?

kostix
  • 51,517
  • 14
  • 93
  • 176
  • 2
    Possible duplicate of ["Least Astonishment" and the Mutable Default Argument](http://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument) – DYZ Mar 14 '17 at 23:48
  • Sorry for giving a bad example.. But my question really is when will function object be initialized.. – user7688889 Mar 14 '17 at 23:59
  • 1
    Python is a scripting language, and this actually defines the semantics on what you see in any Python script file: everything is executed from top to bottom, and as soon as the parser parses out `def name(arguments):` it knowns it deals with the definition of a function, reads its body, parses it and if no errors are encountered, it "creates" a function ready to be executed in the current scope right away. – kostix Mar 15 '17 at 07:06

2 Answers2

0

[] creates a list and, for efficiency reasons, when a list is passed, it isn't duplicated or passed by value; it is sent by reference. A similar thing is happening with this. So, firstly all def's are initialized by Python. Then your code is run. However, the initializer has already created the list.

>>> id(add_to_list())
12516768
>>> id(add_to_list())
12516768
>>> id(add_to_list())
12516768

Excerpt from http://effbot.org/zone/default-values.htm

Notice how they have the same id? That's because it's returning the same instance of list every time. Thus, l = [] isn't creating a new instance at run time. So, we keep on appending to the same instance.

That is why we don't experience this behavior with ints, floats, and etc.

Consider your code:

def add_to_list(l = []):
    l.append("foo")
    print(l)
add_to_list()
add_to_list()

Then it's output:

['foo']
['foo', 'foo']

Now consider this similar function:

def add_to_list():
    l = []
    l.append("foo")
    print(l)
add_to_list()
add_to_list()

The output will be:

['foo']
['foo']

That's because the l = [] is run after the constructors are initialized (in live time). When you consider the first code, you will see that the constructor is ran first, then the code executes live time.

Neil
  • 14,063
  • 3
  • 30
  • 51
-1

def is executed whenever you hit it in parsing the source file. It defines the function. This means that the body of the function is assigned to the name, the parameters are included in the "signature" (calling format), etc. IN other words, the function is now ready to call from anywhere below that point, within the scope of the containing program.

Since l is a list, it's bound to whatever you pass into the function call. If you pass in a list, then it's bound by reference to that list, a mutable object.

As to your specific case, there's really no use case that will make sense: since you have to pass an object with an append method, anything you supply will have a value: it will never use the default value. The only way to get that default value into play is to call with empty parentheses, in which case there's no way to get the value back to the calling program (since you return nothing).

Thus, when you call the routine a second time, it appears that you're using the same list you passed the first time. That list already has the "foo" element you added that first time. Here's some test code and the output to illustrate the effect:

def add_to_list(l = []):
    l.append("foo")
    print "l =", l

empty = []
add_to_list(empty)
print "empty #1", empty
add_to_list(empty)
print "empty #2", empty

add_to_list()

Output:

l = ['foo']
empty #1 ['foo']
l = ['foo', 'foo']
empty #2 ['foo', 'foo']
l = ['foo']

Does that clarify things?

Prune
  • 76,765
  • 14
  • 60
  • 81