Objects and Types¶
Passing Arguments and Returning Values¶
Argument Passing¶
When we pass an object reference to a function, we’re essentially assigning from an actual argument reference, in this case m
to the formal argument reference, in this case k
. Assignment causes the reference being assigned to being referred to the same object as the reference being assigned from, which is what’s going on here:
>>> m = [9, 15, 24]
>>> def modify(k):
... k.append(39)
... print("k =", k)
...
>>> modify(m)
k = [9, 15, 24, 39]
>>> m
[9, 15, 24, 39]
If you want a function to modify the copy of an object, it’s the responsibility of the function to do the copying.
Replacing Argument Value¶
f
still refers to the unmodified list, this time the function didn’t modify the object it passed in.
>>> f = [14, 23, 37]
>>> def replace(g):
... g = [17, 28, 45]
... print("g =", g)
...
>>> replace(f)
g = [17, 28, 45]
>>> f
[14, 23, 37]
The object reference named f
was assigned to the formal argument named g
, so g
and f
did refer the the same object, just as in previous example. However in the first line in the function we reassigned the reference g
to point to a newly constructed list. So within the function, the reference to the original list was overwritten, although the orignal list was still pointed to by the f
reference outside the function.
Mutable Arguments¶
>>> def replace_contents(g):
... g[0] = 17
... g[1] = 28
... g[2] = 45
... print("g =", g)
...
>>> f = [14, 23, 37]
>>> replace_contents(f)
g = [17, 28, 45]
>>> f
[17, 28, 45]
Function arguments are transferred using pass-by-object-reference.
References to objects are copied, not the objects themselves.
>>> def f(d):
... return d
...
>>> c = [6, 10, 16]
>>> e = f(c)
>>> c is e
True
Function Arguments¶
Default Argument Values¶
Arguments with default values must come after those without default values.
>>> def banner (message, border='-'):
... line = border * len(message)
... print (line)
... print(message)
... print(line)
...
>>> banner("Howzit my bru!")
--------------
Howzit my bru!
--------------
>>> banner("Sun, Moon, Stars", "*")
****************
Sun, Moon, Stars
****************
>>> banner("Sun, Moon, Stars", border="*")
****************
Sun, Moon, Stars
****************
>>> banner(border=".", message="Hello from Earth, we come in peace!")
...................................
Hello from Earth, we come in peace!
...................................
When Are Default Values Evaluated?¶
>>> import time
>>> time.ctime()
'Fri Feb 12 20:26:02 2021'
>>> def show_default(arg=time.ctime()):
... print(arg)
...
>>> show_default()
Fri Feb 12 20:26:35 2021
>>> show_default()
Fri Feb 12 20:26:35 2021
>>> show_default()
Fri Feb 12 20:26:35 2021
Remember that
def
is a statement executed at runtimeDefault arguments are evaluated when
def
is executedImmutable default values don’t cause problems
Mutable default values can cause confusing effects
Mutable Default Values¶
>>> def add_spam(menu=[]):
... menu.append("spam")
... return menu
...
>>> breakfast = ['bacon', 'eggs']
>>> add_spam(breakfast)
['bacon', 'eggs', 'spam']
>>> lunch = ['baked beans']
>>> add_spam(lunch)
['baked beans', 'spam']
>>> add_spam()
['spam']
>>> add_spam()
['spam', 'spam']
>>> add_spam()
['spam', 'spam', 'spam']
The empty list that’s used for the default argument is created once when the
def
statement is executed. The first time, spam is added, when adding second time, list still contains spam.So always use immutable objects for default values!
Immutable Default Values¶
>>> def add_spam(menu=None):
... if menu is None:
... menu = []
... menu.append('spam')
... return menu
...
>>> add_spam()
['spam']
>>> add_spam()
['spam']
>>> add_spam()
['spam']
Python’s Type System¶
>>> def add(a, b):
... return a+b
...
>>> add(5,7)
12
>>> add(3.1, 2.4)
5.5
>>> add("news", "paper")
'newspaper'
>>> add([1, 6], [21, 107])
[1, 6, 21, 107]
>>> add("The answer is", 42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in add
TypeError: can only concatenate str (not "int") to str
Python will not generally perform implicit conversions between types.
Scopes¶
Type declarations are unnecessary in Python.
Names can be rebound as necessary to objects of any type.
Name resolution to objects is managed by scopes and scoping rules.
Scopes in Python¶
(LEGB)
L ocal - Inside the current function
E nclosing - Inside enclosing functions
G lobal - At the tope level of the module
B uilt-in - In the special builtins module
Scopes in python don’t correspond source code blocks