3.4 KiB
[ Index | Exercise 5.1 | Exercise 5.3 ]
Exercise 5.2
Objectives:
- Returning values from functions
In this exercise, we briefly look at problems related to returning values from functions. At first glance, it seems like this should be straightforward, but there are some subtle problems that arise.
(a) Returning Multiple Values
Suppose you were writing code to parse configuration files consisting of lines like this:
name=value
Write a function parse_line(line)
that takes such a line
and returns both the associated name and value. The common convention
for returning multiple values is to return them in a tuple. For
example:
>>> parse_line('email=guido@python.org')
'email', 'guido@python.org')
(>>> name, val = parse_line('email=guido@python.org')
>>> name
'email'
>>> val
'guido@python.org'
>>>
(b) Returning Optional Values
Sometimes a function might return an optional value–possibly as a
mechanism for indicating success or failure. The most common convention
is to use None
as a representation for a missing value.
Modify the parse_line()
function above so that it either
returns a tuple on success or None
on bad data. For
example:
>>> parse_line('email=guido@python.org')
'email', 'guido@python.org')
(>>> parse_line('spam') # Returns None
>>>
Design discussion: Would it be better for the
parse_line()
function to raise an exception on malformed
data?
(c) Futures
Sometimes Python code executes concurrently via threads or processes. To illustrate, try this example:
>>> import time
>>> def worker(x, y):
print('About to work')
20)
time.sleep(print('Done')
return x + y
>>> worker(2, 3) # Normal function call
About to work
Done5
>>>
Now, launch worker()
into a separate thread:
>>> import threading
>>> t = threading.Thread(target=worker, args=(2, 3))
>>> t.start()
About to work>>>
Done
Carefully notice that the result of the calculation appears nowhere.
Not only that, you don’t even know when it’s going to be completed.
There is a certain coordination problem here. The convention for
handling this case is to wrap the result of a function in a
Future
. A Future
represents a future result.
Here’s how it works:
>>> from concurrent.futures import Future
>>> # Wrapper around the function to use a future
>>> def do_work(x, y, fut):
fut.set_result(worker(x,y))
>>> fut = Future()
>>> t = threading.Thread(target=do_work, args=(2, 3, fut))
>>> t.start()
About to work >>> result = fut.result()
Done>>> result
5
>>>
You’ll see this kind of pattern a lot of if working with thread pools, processes, and other constructs. For example:
>>> from concurrent.futures import ThreadPoolExecutor
>>> pool = ThreadPoolExecutor()
>>> fut = pool.submit(worker, 2, 3)
About to work>>> fut
<Future at 0x102157080 state=running>
>>> fut.result()
Done5
>>>
[ Solution | Index | Exercise 5.1 | Exercise 5.3 ]
>>>
Advanced Python Mastery
...
A course by dabeaz
...
Copyright 2007-2023
.
This work is licensed under a Creative Commons
Attribution-ShareAlike 4.0 International License