What if you want a function to accept any number of arguments?
The built-in max function allows that:
max(1, 2) # 2
max(10, 30, 20) # 30
max(-2, 33, -40, 400, 321) # 400
That's possible by using the *args syntax in the function definition.
def max(*args):
# Do something with *args
One way to use *args is to send those arguments into
another function.
def min_and_max(*args):
return min(*args), max(*args)
min_and_max(-2, 33, -40, 400, 321) # -40, 400
A HOF can return a function that can be called with any number of arguments, and then forward those arguments inside the returned function.
def printed(f):
def print_and_return(*args):
result = f(*args)
print('Result:', result)
return result
return print_and_return
printed_max = printed(max)
printed_max(-2, 33, -40, 400, 321)
Currying: Converting a function that takes multiple arguments into a single-argument higher-order function.
A function that currys any two-argument function:
def curry2(f):
def g(x):
def h(y):
return f(x, y)
return h
return g
from operator import add
make_adder = curry2(add)
make_adder(2)(3)
curry2 = lambda f: lambda x: lambda y: f(x, y)
Whenever another function requires a function that only takes one argument:
def transform_numbers(num1, num2, num3, transform):
return transform(num1), transform(num2), transform(num3)
transform_numbers(3, 4, 5, curry2(add)(60))
Alternate approach:
transform_numbers(3, 4, 5, lambda x: add(60, x))
Turning a generalized function into a specialized function:
def html_tag(tag_name, text):
return "<" + tag_name + ">" + text + "</" + tag_name + ">"
p_tag = curry2(html_tag)("p")
p_tag("hello hello")
Alternate approach:
import functools
p_tag = functools.partial(html_tag, "p")
p_tag("hello hello")
🥦 It's good for you!
CS61A introduces many concepts that aren't standard Python practice, but that show up in other languages.
Currying is a very common practice in functional programming languages like Haskell or Clojure.
WWPD exercises test our understanding of how Python evaluates code and what it chooses to display in the shell.
| The expression | Evaluates to | Interactive output |
|---|---|---|
5
| 5
| 5
|
print(5)
| None
| 5
|
print(print(5))
| None
| 5None
|
>> 5
5
>>> print(5)
5
>>> print(print(5))
5
None
def delay(arg):
print('delayed')
def g():
return arg
return g
| The expression | Evaluates to | Interactive output |
|---|---|---|
delay(6)()
| 6
| delayed6
|
delay(delay)()(6)()
| 6
|
delayeddelayed6
|
print(delay(print)()(4))
| None
|
delayed4None
|
def pirate(arggg):
print('matey')
def plunder(arggg):
return arggg
return plunder
| The expression | Evaluates to | Interactive output |
|---|---|---|
pirate('treasure')('scurvy')
| 'scurvy'
| matey'scurvy'
|
add(pirate(3)(square)(4), 1)
| 17
|
matey17
|
pirate(pirate(pirate))(5)(7)
| Error
|
mateymateyError
|
A name evaluates to the value bound to that name in the earliest frame of the current environment in which that name is found.
def horse(mask):
horse = mask
def mask(horse):
return horse
return horse(mask)
mask = lambda horse: horse(2)
horse(mask)
| horse | ||
| mask | ||
| Return value |
| Return value |
| Return value |
def remove(n, digit):
"""Return digits of non-negative N
that are not DIGIT, for some
non-negative DIGIT less than 10.
>>> remove(231, 3)
21
>>> remove(243132, 2)
4313
"""
kept = 0
digits = 0
while ___________________________:
last = n % 10
n = n // 10
if __________________________:
kept = __________________
digits = ________________
return ___________________________
def remove(n, digit):
"""Return digits of non-negative N
that are not DIGIT, for some
non-negative DIGIT less than 10.
>>> remove(231, 3)
21
>>> remove(243132, 2)
4313
"""
kept = 0
digits = 0
while n > 0:
last = n % 10
n = n // 10
if last != digit:
kept = kept + (last * 10 ** digits)
digits = digits + 1
return kept