Q. Can I use the statement return in a function without specifying a value?
A. Yes. Technically, it returns the None object, which is the sole value of the type NoneType.
Q. What happens if a function has one control flow that leads to a return statement that returns a value but another control flow that reaches the end of the function body?
A. It would be poor style to define such a function, because doing so would place a severe burden on the function’s callers: the callers would need to know under which circumstances the function returns a value, and under which circumstances it returns None.
Q. What happens if I compose code in the body of a function that appears after the return statement?
A. Once a return statement is reached, control returns to the caller. So any code in the body of a function that appears after a return statement is useless; it is never executed. In Python, it is poor style, but not illegal to define such a function.
Q. What happens if I define two functions with the same name (but possibly a different number of arguments) in the same .py file?
A. This is known as function overloading, which is embraced by many programming languages. Python, however, is not one of those languages: the second function definition will overwrite the first one. You can often achieve the same effect by using default arguments.
Q. What happens if I define two functions with the same name in different files?
A. That is fine. For example, it would be good design to have a function named pdf() in gauss.py that computes the Gaussian probability density function and another function named pdf() in cauchy.py that computes the Cauchy probability density function. In SECTION 2.2 you will learn how to call functions defined in different .py files.
Q. Can a function change the object to which a parameter variable is bound?
A. Yes, you can use a parameter variable on the left side of an assignment statement. However, many Python programmers consider it poor style to do so. Note that such an assignment statement has no effect in the client.
Q. The issue with side effects and mutable objects is complicated. Is it really all that important?
A. Yes. Properly controlling side effects is one of a programmer’s most important tasks in large systems. Taking the time to be sure that you understand the difference between passing arrays (which are mutable) and passing integers, floats, booleans, and strings (which are immutable) will certainly be worthwhile. The very same mechanisms are used for all other types of data, as you will learn in CHAPTER 3.
Q. How can I arrange to pass an array to a function in such a way that the function cannot change the elements in the array?
A. There is no direct way to do so. In SECTION 3.3 you will see how to achieve the same effect by building a wrapper data type and passing an object of that type instead. You will also see how to use Python’s built-in tuple data type, which represents an immutable sequence of objects.
Q. Can I use a mutable object as a default value for an optional argument?
A. Yes, but it may lead to unexpected behavior. Python evaluates a default value only once, when the function is defined (not each time the function is called). So, if the body of a function modifies a default value, subsequent function calls will use the modified value. Similar difficulties arise if you initialize the default value by calling an impure function. For example, after Python executes the code fragment
def append(a=, x=random.random()): a += [x] return a b = append() c = append()
b and c are aliases for the same array of length 2 (not 1), which contains one float repeated twice (instead of two different floats).