|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +'''Item 18 from Effective Python''' |
| 4 | + |
| 5 | + |
| 6 | +# Example 1 |
| 7 | +''' say you want to log some debug information. With a fixed number of |
| 8 | +arguments, you would need a function that takes a message and a list of values |
| 9 | +''' |
| 10 | +print('Example 1:\n==========') |
| 11 | + |
| 12 | +def log(message, values): |
| 13 | + if not values: |
| 14 | + print(message) |
| 15 | + else: |
| 16 | + values_str = ', '.join(str(x) for x in values) |
| 17 | + print('%s: %s' % (message, values_str)) |
| 18 | + |
| 19 | +log('My numbers are', [1, 2]) |
| 20 | +log('Hi there', []) |
| 21 | + |
| 22 | + |
| 23 | +# Example 2 |
| 24 | +''' The first parameter for the log message is required, whereas any number of |
| 25 | +subsequent positional arguments are optional. The function body doesn't need to |
| 26 | +change, only the callers do ''' |
| 27 | +print('\nExample 2:\n==========') |
| 28 | + |
| 29 | +def log(message, *values): # The only difference |
| 30 | + if not values: |
| 31 | + print(message) |
| 32 | + else: |
| 33 | + values_str = ', '.join(str(x) for x in values) |
| 34 | + print('%s: %s' % (message, values_str)) |
| 35 | + |
| 36 | +log('My numbers are', 1 ,2) |
| 37 | +log('Hi there') # Much better |
| 38 | + |
| 39 | + |
| 40 | +# Example 3 |
| 41 | +''' If you already have a list and want to call a variable argument function |
| 42 | +like log , you can do this by using the * operator. This instructs Python to |
| 43 | +pass items from the sequence as positional arguments ''' |
| 44 | +print('\nExample 3:\n==========') |
| 45 | + |
| 46 | +favourites = [7, 33, 99] |
| 47 | +log('Favourite colours', *favourites) |
| 48 | + |
| 49 | + |
| 50 | +# Example 4 |
| 51 | +''' the variable arguments are always turned into a tuple before they are |
| 52 | +passed to your function. This means that if the caller of your function uses |
| 53 | +the * operator on a generator, it will be iterated until it's exhausted ''' |
| 54 | +print('\nExample 4:\n==========') |
| 55 | + |
| 56 | +def my_generator(): |
| 57 | + for i in range(10): |
| 58 | + yield i |
| 59 | + |
| 60 | + |
| 61 | +def my_func(*args): |
| 62 | + print(args) |
| 63 | + |
| 64 | + |
| 65 | +it = my_generator() |
| 66 | +my_func(*it) |
| 67 | + |
| 68 | + |
| 69 | +# Example 5 |
| 70 | +''' If you try to add a positional argument in the front of the argument list, |
| 71 | +existing callers will subtly break if they aren't updated ''' |
| 72 | +print('\nExample 5:\n==========') |
| 73 | + |
| 74 | +def log(sequence, message, *values): |
| 75 | + if not values: |
| 76 | + print('%s: %s' % (sequence, message)) |
| 77 | + else: |
| 78 | + values_str = ', '.join(str(x) for x in values) |
| 79 | + print('%s: %s: %s' % (sequence, message, values_str)) |
| 80 | + |
| 81 | + |
| 82 | +log(1, 'Favourites', 7, 33) # New usage is OK |
| 83 | +log('Favourite numbers', 7, 33) # Old usage breaks |
0 commit comments