diff -r babb9479b79f Doc/faq/design.rst --- a/Doc/faq/design.rst Thu Mar 20 11:00:29 2014 -0500 +++ b/Doc/faq/design.rst Mon Mar 24 14:18:08 2014 +0000 @@ -712,62 +712,6 @@ sloppy and not write test cases at all. -Why are default values shared between objects? ----------------------------------------------- - -This type of bug commonly bites neophyte programmers. Consider this function:: - - def foo(mydict={}): # Danger: shared reference to one dict for all calls - ... compute something ... - mydict[key] = value - return mydict - -The first time you call this function, ``mydict`` contains a single item. The -second time, ``mydict`` contains two items because when ``foo()`` begins -executing, ``mydict`` starts out with an item already in it. - -It is often expected that a function call creates new objects for default -values. This is not what happens. Default values are created exactly once, when -the function is defined. If that object is changed, like the dictionary in this -example, subsequent calls to the function will refer to this changed object. - -By definition, immutable objects such as numbers, strings, tuples, and ``None``, -are safe from change. Changes to mutable objects such as dictionaries, lists, -and class instances can lead to confusion. - -Because of this feature, it is good programming practice to not use mutable -objects as default values. Instead, use ``None`` as the default value and -inside the function, check if the parameter is ``None`` and create a new -list/dictionary/whatever if it is. For example, don't write:: - - def foo(mydict={}): - ... - -but:: - - def foo(mydict=None): - if mydict is None: - mydict = {} # create a new dict for local namespace - -This feature can be useful. When you have a function that's time-consuming to -compute, a common technique is to cache the parameters and the resulting value -of each call to the function, and return the cached value if the same value is -requested again. This is called "memoizing", and can be implemented like this:: - - # Callers will never provide a third parameter for this function. - def expensive(arg1, arg2, _cache={}): - if (arg1, arg2) in _cache: - return _cache[(arg1, arg2)] - - # Calculate the value - result = ... expensive computation ... - _cache[(arg1, arg2)] = result # Store result in the cache - return result - -You could use a global variable containing a dictionary instead of the default -value; it's a matter of taste. - - Why is there no goto? --------------------- diff -r babb9479b79f Doc/faq/programming.rst --- a/Doc/faq/programming.rst Thu Mar 20 11:00:29 2014 -0500 +++ b/Doc/faq/programming.rst Mon Mar 24 14:18:08 2014 +0000 @@ -499,6 +499,62 @@ occur when the module is initialized. +Why are default values shared between objects? +---------------------------------------------- + +This type of bug commonly bites neophyte programmers. Consider this function:: + + def foo(mydict={}): # Danger: shared reference to one dict for all calls + ... compute something ... + mydict[key] = value + return mydict + +The first time you call this function, ``mydict`` contains a single item. The +second time, ``mydict`` contains two items because when ``foo()`` begins +executing, ``mydict`` starts out with an item already in it. + +It is often expected that a function call creates new objects for default +values. This is not what happens. Default values are created exactly once, when +the function is defined. If that object is changed, like the dictionary in this +example, subsequent calls to the function will refer to this changed object. + +By definition, immutable objects such as numbers, strings, tuples, and ``None``, +are safe from change. Changes to mutable objects such as dictionaries, lists, +and class instances can lead to confusion. + +Because of this feature, it is good programming practice to not use mutable +objects as default values. Instead, use ``None`` as the default value and +inside the function, check if the parameter is ``None`` and create a new +list/dictionary/whatever if it is. For example, don't write:: + + def foo(mydict={}): + ... + +but:: + + def foo(mydict=None): + if mydict is None: + mydict = {} # create a new dict for local namespace + +This feature can be useful. When you have a function that's time-consuming to +compute, a common technique is to cache the parameters and the resulting value +of each call to the function, and return the cached value if the same value is +requested again. This is called "memoizing", and can be implemented like this:: + + # Callers will never provide a third parameter for this function. + def expensive(arg1, arg2, _cache={}): + if (arg1, arg2) in _cache: + return _cache[(arg1, arg2)] + + # Calculate the value + result = ... expensive computation ... + _cache[(arg1, arg2)] = result # Store result in the cache + return result + +You could use a global variable containing a dictionary instead of the default +value; it's a matter of taste. + + How can I pass optional or keyword parameters from one function to another? --------------------------------------------------------------------------- @@ -548,6 +604,65 @@ the values ``42``, ``314``, and ``somevar`` are arguments. +Why did changing list 'a' also change list 'b'? +------------------------------------------------ +It didn't. In cases where this appears to happen, ``a`` and ``b`` are the same +list. + +Variables are assigned the value of a reference to an object. However, +depending on whether an object is mutable or immutable, the behavior of +assigning a variable to another variable can appear to differ. + +Integers, strings, and tuples are examples of immutable objects. When an +immutable object is altered, a new object is created and only the variable where +the object was created is updated to reference the new object. +For example:: + + >>> x = 1 + >>> y = x + >>> x = x + 1 + >>> x + 2 + >>> y + 1 + +Because integers are immutable, ``x`` points to the new object whereas ``y`` +still points to the old object. Here is an example with tuples, which like +integers are immutable:: + + >>> a = (1,2) + >>> b = a + >>> a = a + (3,) + >>> a + (1, 2, 3) + >>> b + (1, 2) + +However, if the object being referenced is mutable, then the object can be +changed with no new object being created, as in the case of list mutation:: + + >>> a = [1, 2] + >>> b = a + >>> a.append(3) + >>> a + [1, 2, 3] + >>> b + [1, 2, 3] + +In the above example, both variables ``a`` and ``b`` reference the same object. +However, it is important to note that although lists are mutable, not all +operations mutate lists; in the case of concatenating lists, a new list is +created and therefore the variables ``x`` and ``y`` in the example below +reference different objects:: + + >>> x = [1, 2] + >>> y = x + >>> x = x + [3] + >>> x + [1, 2, 3] + >>> y + [1, 2] + How do I write a function with output parameters (call by reference)? ---------------------------------------------------------------------