Initial commit
This commit is contained in:
126
Exercises/ex5_2.md
Normal file
126
Exercises/ex5_2.md
Normal file
@@ -0,0 +1,126 @@
|
||||
\[ [Index](index.md) | [Exercise 5.1](ex5_1.md) | [Exercise 5.3](ex5_3.md) \]
|
||||
|
||||
# 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:
|
||||
|
||||
```python
|
||||
>>> 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:
|
||||
|
||||
```python
|
||||
>>> 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:
|
||||
|
||||
```python
|
||||
>>> import time
|
||||
>>> def worker(x, y):
|
||||
print('About to work')
|
||||
time.sleep(20)
|
||||
print('Done')
|
||||
return x + y
|
||||
|
||||
>>> worker(2, 3) # Normal function call
|
||||
About to work
|
||||
Done
|
||||
5
|
||||
>>>
|
||||
```
|
||||
|
||||
Now, launch `worker()` into a separate thread:
|
||||
|
||||
```python
|
||||
>>> 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:
|
||||
|
||||
```python
|
||||
>>> 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:
|
||||
|
||||
```python
|
||||
>>> from concurrent.futures import ThreadPoolExecutor
|
||||
>>> pool = ThreadPoolExecutor()
|
||||
>>> fut = pool.submit(worker, 2, 3)
|
||||
About to work
|
||||
>>> fut
|
||||
<Future at 0x102157080 state=running>
|
||||
>>> fut.result()
|
||||
Done
|
||||
5
|
||||
>>>
|
||||
```
|
||||
|
||||
\[ [Solution](soln5_2.md) | [Index](index.md) | [Exercise 5.1](ex5_1.md) | [Exercise 5.3](ex5_3.md) \]
|
||||
|
||||
----
|
||||
`>>>` Advanced Python Mastery
|
||||
`...` A course by [dabeaz](https://www.dabeaz.com)
|
||||
`...` Copyright 2007-2023
|
||||
|
||||
. This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)
|
||||
Reference in New Issue
Block a user