Introduction
------------
Here is a an example
of a function:
>>>
def fib(n): # write Fibonacci series
up to n
... """Print a Fibonacci series
up to n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>>
# Now call the function we just defined:
>>>
fib(2000)
0 1 1 2
3 5 8 13 21 34 55 89 144 233 377 610 987 1597
>>>
>>>
fib.__doc__
Print a
Fibonacci series up to n.
>>>
The keyword def
introduces a function definition. It must be followed by the
function name and the
parenthesized list of formal parameters. The statements
that form the body of
the function start at the next line, and must be indented.
The first statement
of the function body can optionally be a string literal;
this string literal
is the function’s documentation string, or docstring. (More
about docstrings can
be found in the section Documentation Strings.) There are
tools which use
docstrings to automatically produce online or printed
documentation, or to
let the user interactively browse through code; it’s good
practice to include
docstrings in code that you write, so make a habit of it.
The execution of a
function introduces a new symbol table used for the local
variables of the
function. More precisely, all variable assignments in a
function store the
value in the local symbol table; whereas variable references
first look in the
local symbol table, then in the local symbol tables of
enclosing functions,
then in the global symbol table, and finally in the table
of built-in names.
Thus, global variables cannot be directly assigned a value
within a function
(unless named in a global statement), although they
may be referenced.
The actual parameters
(arguments) to a function call are introduced in the local
symbol table of the
called function when it is called; thus, arguments are
passed using call by
value (where the value is always an object reference, not
the value of the
object). [1] When a function calls another function, a new
local symbol table is
created for that call.
A function definition
introduces the function name in the current symbol table.
The value of the
function name has a type that is recognized by the interpreter
as a user-defined
function. This value can be assigned to another name which can
then also be used as
a function. This serves as a general renaming mechanism:
>>>
fib
>>>
f = fib
>>>
f(100)
0 1 1 2
3 5 8 13 21 34 55 89
Coming from other
languages, you might object that fib is not a function but a
procedure since it
doesn’t return a value. In fact, even functions without a
return statement do
return a value, albeit a rather boring one. This value is
called None (it’s a
built-in name). Writing the value None is normally
suppressed by the
interpreter if it would be the only value written. You can see
it if you really want
to using print():
>>>
fib(0)
>>>
print(fib(0))
None
>>>
It is simple to write
a function that returns a list of the numbers of the
Fibonacci series,
instead of printing it:
>>>
def fib2(n): # return Fibonacci series up to n
... """Return a list containing
the Fibonacci series up to n."""
... result = []
... a, b = 0, 1
... while a < n:
... result.append(a) # see below
... a, b = b, a+b
... return result # script terminates here,
anything under will not be read
...
>>>
f100 = fib2(100) # call it
>>>
f100 # write the result
[0, 1,
1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
This example, as
usual, demonstrates some new Python features:
- The return statement returns with a value
from a function. return without an
expression argument returns None. Falling
off the end of a function also
returns None.
- The statement result.append(a) calls a
method of the list object result. A
method is a function that ‘belongs’ to an
object and is named
obj.methodname, where obj is some object
(this may be an expression), and
methodname is the name of a method that is
defined by the object’s type.
Different types define different methods.
Methods of different types may
have the same name without causing
ambiguity. (It is possible to define your
own object types and methods, using
classes, see Classes) The method
append() shown in the example is defined
for list objects; it adds a new
element at the end of the list. In this
example it is equivalent to
result = result + [a], but more efficient.
Default Arguments
-----------------
If you don't
specify an argument to pass,
Python can provide a default argument for you. |
#
code
def
provide_or_ignore(a='no argument?'):
return(a)
print(provide_or_ignore())
print(provide_or_ignore(a='now
we are talking!'))
# output
no
argument?
now
we are talking!
|
Here is a more
detailed example.
The function on the
right can be called
in several ways:
- only the
mandatory argument:
ask_ok('Do you really want to quit?')
- mandatory
argument + 1 of the optional arguments:
ask_ok('OK to overwrite the file?', 2)
- all arguments
given:
ask_ok('OK to overwrite the file?', 2,
'only yes or no!')
The `in` keyword tests whether or not a sequence contain a certain value |
def
ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise IOError('uncooperative
user')
print(complaint)
|
The default value
is evaluated at the point of function
definition. |
#
code
i = 5
def
f(arg=i):
print(arg)
i = 6
f()
# output 5 |
Default value is
evaluated only once.
When default is a mutable object like list, dictionary or an instance, the value is shared and accumulated between function calls. |
#
default value will accumulate between calls
def
f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
# output
[1]
[1,
2]
[1,
2, 3]
#
default value doesn't accumulate
def
f(a, L=None):
if L is None:
L = []
L.append(a)
return L
# output
[1]
[2]
[3]
|
Keyword Arguments
-----------------
- functions may
accept arguments in the form of `kwarg=value`, `*kwarg`, or
`**kwarg`
- there are rules on
how you can pass these to functions
This function accepts
1 required argument (voltage) and 3 optional arguments.
def
parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't",
action, end=' ')
print("if you put", voltage,
"volts through it.")
print("-- Lovely plumage, the",
type)
print("-- It's", state,
"!")
It can be called in
any of the following ways:
parrot(1000) # 1
positional argument
parrot(voltage=1000) # 1 keyword
argument
parrot(voltage=1000000,
action='VOOOOOM') # 2 keyword
arguments
parrot(action='VOOOOOM',
voltage=1000000) # 2 keyword
arguments
parrot('a
million', 'bereft of life', 'jump')
# 3 positional arguments
parrot('a
thousand', state='pushing up the daisies')
# 1 positional, 1 keyword
It cannot be called
using the ff:
parrot() # required argument
missing
parrot(voltage=5.0,
'dead') # non-keyword argument after a
keyword argument
parrot(110,
voltage=220) # duplicate value for
the same argument
parrot(actor='John
Cleese') # unknown keyword argument
No argument may
receive more than 1 value. Example:
>>>
def function(a):
... pass
...
>>>
function(0, a=0)
Traceback
(most recent call last):
File "", line 1, in ?
TypeError:
function() got multiple values for keyword argument 'a'
Using `*kwarg` allows
the function to accept multiple arguments defined by the
user while `**kwarg`
allows it to receive a dictionary (also defined by the
user).
#
function
def
cheeseshop(kind, *arguments, **keywords):
print("-- Do you have any", kind,
"?")
print("-- I'm sorry, we're all out
of", kind)
for arg in arguments:
print(arg)
print("-" * 40)
keys = sorted(keywords.keys()) # this sort
the user-defined dictionary
for kw in keys:
print(kw, ":", keywords[kw])
#
calling the function
cheeseshop("Limburger",
"It's very runny, sir.",
"It's really very, VERY runny,
sir.",
shopkeeper="Michael
Palin",
client="John Cleese",
sketch="Cheese Shop
Sketch")
#
output
-- Do
you have any Limburger ?
-- I'm
sorry, we're all out of Limburger
It's
very runny, sir.
It's
really very, VERY runny, sir.
----------------------------------------
client
: John Cleese
shopkeeper
: Michael Palin
sketch
: Cheese Shop Sketch
Arbitrary Argument Lists
------------------------
- least frequently
used method of passing arguments to a function
- this method also
uses `*kwarg` -> variable number of arguments
- arguments will be
wrapped inside a tuple
Zero or more normal
arguments may occur before
the variable number of arguments. |
def
write_multiple_items(file, separator, *args):
file.write(separator.join(args))
|
Any parameters
appear after `*kwarg` must be
keyword arguments only. |
>>>
def concat(*args, sep="/"):
... return sep.join(args)
...
>>>
concat("earth", "mars", "venus")
'earth/mars/venus'
>>>
concat("earth", "mars", "venus",
sep=".")
'earth.mars.venus'
|
Unpacking Argument Lists
------------------------
- argument lists may
be generated by unpacking a list or a dictionary
Unpacking a list
|
>>>
list(range(3, 6)) # normal call with
separate arguments
[3,
4, 5]
>>>
args = [3, 6]
>>>
list(range(*args)) # call with
arguments unpacked from a list
[3,
4, 5]
|
Unpacking a
dictionary
|
>>>
def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot
wouldn't", action, end=' ')
... print("if you put", voltage,
"volts through it.", end=' ')
... print("E's", state,
"!")
...
>>>
d = {"voltage": "four million", "state":
"bleedin' demised", "action": "VOOM"}
>>>
parrot(**d)
--
This parrot wouldn't VOOM if you put four million volts through it. E's
bleedin' demised !
|
Lambda Expressions
------------------
- special type of
functions that return a function
- doesn't include a
`return` statement -- always contains an expression that is
always returned
- see example uses
below
Getting the sum of
2 numbers
|
>>>
sum = lambda x, y : x + y
>>>
sum(3,4)
7
>>>
|
Lambda functions
can also reference
variables from the containing scope |
>>>
def make_incrementor(n):
... return lambda x: x + n
...
>>>
f = make_incrementor(42)
>>>
f(0)
42
>>>
f(1)
43
|
Passes a small
function as an
argument |
>>>
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>>
pairs.sort(key=lambda pair: pair[1])
>>>
pairs
[(4,
'four'), (1, 'one'), (3, 'three'), (2, 'two')]
|
Documentation Strings aka docstrings
------------------------------------
- docstrings are
string literals that describe your code
- see below the
format, examples, and rules in writing them
A single line
docstring
|
>>>
>>>
def test():
... """just a
sample""" # first line
must be short and concise summary
... # of your code's
purpose
>>>
test.__doc__
'just
a sample'
>>>
|
If more than 1 line
is required, you
must put a blank line after the 1st line to separate the summary from the rest of the description. The 1st non-blank line aftr the 1st line determines the amount of indentation for the entire docstring. |
>>>
def my_function():
... """Do nothing, but
document it.
...
... No, really, it doesn't do anything.
... You may use this function without harm
... """
... pass
...
>>>
print(my_function.__doc__)
Do
nothing, but document it.
No, really, it doesn't do anything.
|
Some examples of
common docstrings
|
>>>
print(len.__doc__)
Return
the number of items in a container.
>>>
>>>
>>>
print(map.__doc__)
map(func,
*iterables) --> map object
Make
an iterator that computes the function using arguments from
each
of the iterables. Stops when the
shortest iterable is exhausted.
>>>
>>>
print(filter.__doc__)
filter(function
or None, iterable) --> filter object
Return
an iterator yielding those items of iterable for which function(item)
is
true. If function is None, return the items that are true.
>>>
|
Function Annotations
--------------------
- ways of describing
function arguments
- has no effect on
the code execution
- not commonly used
- annotations are
stored in `__annotations__` attribute of the function
In this examle, a
has no annotation, b is
annotated with 'a string' and c is annotated with int. The return value is annotated with type float. Notice the "->" syntax. |
>>>
def foo(a, b: 'a string', c: int) -> float:
... print(a + b + c)
|
Using the example
above, we can see here
that the annotations have no impact on the execution of function. |
>>>
foo('Hello', ', ', 'World!')
Hello,
World!
>>>
>>>
foo(1, 2, 3)
6
>>>
|
A complex example
with "eggs" being
annotated and at the same time having a default value of "spam". |
>>>
def f(ham: 42, eggs: int = 'spam') -> "Nothing to see here":
... print("Annotations:",
f.__annotations__)
... print("Arguments:", ham, eggs)
...
>>>
f('wonderful')
Annotations:
{'eggs':
Arguments:
wonderful spam
|
Future Statements
-----------------
- Used in Python 2.X
to support Python 3.X syntax
Allows Python 2.X
to use `print('hello')`
together with
`print "hello"`
|
from
__future__ import print_function
|
No comments:
Post a Comment