Defining Functions |
function that writes the Fibonacci series to an arbitrary boundary
>>> def fib(n): # write Fibonacci series less than n ... """Print a Fibonacci series less than 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 1597keyword def introduces a function definition followed by function name and the parenthesized list of formal parameters first statement of the function body can optionally be a string literal string literal is the function's documentation string, or docstring a new symbol table used for the local variables all variable assignments are stored this symbol table variable references by looking in
assumption : helps prevent side-effects exceptions are
all Python functions return a value with default None function that returns a list of the numbers of the Fibonacci series >>> 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 >>> f100 = fib2(100) # call it >>> f100 # write the result [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]the return statement returns a value return without an expression argument returns None function without a return statement returns None the statement result.append(a) calls a method of the list object result |
Default Argument Values |
default arguments
def ask_ok(prompt, retries=4, reminder='Please try again!'): while True: reply = input(prompt) if reply in {'y', 'ye', 'yes'}: return True if reply in {'n', 'no', 'nop', 'nope'}: return False retries = retries - 1 if retries < 0: raise ValueError('invalid user response') print(reminder)in keyword tests whether or not a sequence contains the specified value default values are evaluated at the point of function definition in the defining scope i = 5 def f(arg=i): print(arg) i = 6 f() # prints 5 print(i) # prints 6Important warning : The default value is evaluated only once this makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes this function accumulates the arguments passed to it on subsequent calls def f(a, L=[]): L.append(a) return L print(f(1)) # prints [1] print(f(2)) # prints [1, 2] print(f(3)) # prints [1, 2, 3]to defeat the default behavior of sharing between subsequent calls def f(a, L=None): if L is None: L = [] L.append(a) return L |
Keyword Arguments |
functions can be called using keyword arguments of the form argName=value
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, "!")parrot can be called multiple 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 keywordbelow arguments is a tuple and keywords is a dictionary the * and ** unpack the two arguments 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) for kw in keywords: print(kw, ":", keywords[kw]) |
Special Parameters |
arguments may be passed to a Python function either by position or explicitly by keyword can restrict the way arguments can be passed developer can look at the function definition to determine how args are passed def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): ----------- ---------- ---------- | | | | Positional or keyword | | - Keyword only -- Positional only Positional-or-Keyword Arguments
if / and * are not present in the function definition, arguments may be passed to a function by position or by keyword
Positional-Only Parameters
if positional-only the parameter order matterspositional-only parameters are placed before a / (forward-slash) the / is used to logically separate the positional-only parameters from the rest of the parameters parameters following the / may be positional-or-keyword or keyword-only Keyword-Only Arguments
to mark parameters as keyword-only place an * in the arguments list just before the first keyword-only parameter
Function Examples
arguments may be passed by position or keyword
>>> def standard_arg(arg): ... print(arg)restricted to only use positional parameters >>> def pos_only_arg(arg, /): ... print(arg)only allows keyword arguments >>> def kwd_only_arg(*, arg): ... print(arg)uses all three calling conventions in the same function definition >>> def combined_example(pos_only, /, standard, *, kwd_only): ... print(pos_only, standard, kwd_only) Possible Collisions
function will not return True as 'name' will bind to the first argument
def foo(name, **kwds): return 'name' in kwdsinvocation with 'name' as key in dictionary fails >>> foo(1, **{'name': 2}) Traceback (most recent call last): File "using the / prevents collision >>> def foo(name, /, **kwds): ... return 'name' in kwds >>> foo(1, **{'name': 2}) True Recap
guidance
|
Arbitrary Argument Lists |
function can be called with an arbitrary number of arguments arguments will be wrapped up in a tuple def write_multiple_items(file, separator, *args): file.write(separator.join(args))usually variadic arguments will be last in the list of formal parameters any formal parameters which occur after the *args parameter are ‘keyword-only' arguments >>> 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 |
can use tuple as argument if it is unpacked
>>> 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]can use dictionary as argument if it is unpacked >>> 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 |
small anonymous functions can be created with the lambda keyword
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43can pass lambda 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 |
first line should always be a short, concise summary of the object's purpose no need to explicitly state the object's name or type exception is when name is a verb describing the function operation line should start with capital letter and end with a period if there are more lines the second one should be blank following lines should provide details of calling conventions, side effects, etc. multi-line docstring >>> def my_function(): ... """Do nothing, but document it. ... ... No, really, it doesn't do anything. ... """ ... pass ... >>> print(my_function.__doc__) Do nothing, but document it. No, really, it doesn't do anything. |
Function Annotations |
function annotations are completely optional metadata information about the types used by user-defined functions annotations are stored in the __annotations__ attribute of the function as a dictionary annotations have no effect on any other part of the function >>> def f(ham: str, eggs: str = 'eggs') -> str: ... print("Annotations:", f.__annotations__) ... print("Arguments:", ham, eggs) ... return ham + ' and ' + eggs ... >>> f('spam') Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>} Arguments: spam eggs 'spam and eggs' |
Intermezzo: Coding Style |
PEP 8 has emerged as the style guide that most projects adhere to
|