{"id":"functions-as-arguments-own","slug":"own-functions","title":"Functions that take functions","text":"`sorted`, `min` and `max` get a function as an argument and call it themselves. Your own functions can do the same. A parameter can hold a function just as it holds a number or a list, and you call it with parentheses, like any function:\n\n```python\ndef apply_to_all(numbers, operation):\n    results = []\n    for number in numbers:\n        results.append(operation(number))\n    return results\n\n\ndef double(x):\n    return 2 * x\n\n\nprint(apply_to_all([1, 2, 3], double))\nprint(apply_to_all([1, 2, 3], lambda x: x * x))\nprint(apply_to_all([-4, 5, -6], abs))\n```\n\n```output\n[2, 4, 6]\n[1, 4, 9]\n[4, 5, 6]\n```\n\n`apply_to_all` doesn't know what `operation` does. It only expects a function that takes one number. Which function runs is up to the caller: a named one, a lambda or one of Python's own, such as `abs`, which gives a number without its minus sign. That makes one short function useful for many jobs.\n\nThe function you pass must accept the arguments it will be called with. Here `operation` gets two:\n\n```python\ndef combine(a, b, operation):\n    return operation(a, b)\n\n\nprint(combine(12, 4, lambda x, y: x + y))\nprint(combine(12, 4, lambda x, y: x / y))\nprint(combine(12, 4, max))\n```\n\n```output\n16\n3.0\n12\n```\n\n### A common slip\n\nPass the function, not the result of calling it. Here `double(5)` runs first and gives 10, so `operation` is the number 10, and Python can't call a number:\n\n```python\ndef apply_to_all(numbers, operation):\n    results = []\n    for number in numbers:\n        results.append(operation(number))\n    return results\n\n\ndef double(x):\n    return 2 * x\n\n\nprint(apply_to_all([1, 2, 3], double(5)))\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 12, in <module>\n    print(apply_to_all([1, 2, 3], double(5)))\n          ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^\n  File \"main.py\", line 4, in apply_to_all\n    results.append(operation(number))\n                   ~~~~~~~~~^^^^^^^^\nTypeError: 'int' object is not callable\n```\n\n\"Not callable\" means the value isn't a function. Write `double`, without parentheses.\n\n### A function as a rule\n\nA function argument is a neat way to pass a **rule**: which items to keep, to count or to look for. The function that gets the rule does the looping, and the caller only says what counts. So one `count_matching` can count long words, words with an o or negative numbers:\n\n```python\ndef count_matching(items, condition):\n    count = 0\n    for item in items:\n        if condition(item):\n            count += 1\n    return count\n\n\ndef is_long(word):\n    return len(word) > 4\n\n\nwords = [\"sun\", \"moon\", \"star\", \"comet\", \"planet\", \"nebula\"]\nprint(count_matching(words, is_long))\nprint(count_matching(words, lambda word: \"o\" in word))\nprint(count_matching([3, -1, 8], lambda n: n < 0))\n```\n\n```output\n3\n2\n1\n```\n","task":"The function `keep` returns the items for which the function `wanted` returns `True`. Fill in the blank so that the program prints:\n\n```\n[12, 20]\n['ant', 'cat']\n```\n","kind":"fill","seed":"def keep(items, wanted):\n    result = []\n    for item in items:\n        if [[wanted(item)]]:\n            result.append(item)\n    return result\n\n\nprint(keep([5, 12, 8, 20], lambda n: n > 9))\nprint(keep([\"ant\", \"bee\", \"cat\"], lambda word: word != \"bee\"))\n","solution":"def keep(items, wanted):\n    result = []\n    for item in items:\n        if wanted(item):\n            result.append(item)\n    return result\n\n\nprint(keep([5, 12, 8, 20], lambda n: n > 9))\nprint(keep([\"ant\", \"bee\", \"cat\"], lambda word: word != \"bee\"))\n","hints":["`wanted` is a function. Call it with the item to ask whether the item should be kept.","Calling it looks like any function call: `wanted(item)`. It returns `True` or `False`, which is just what the `if` needs."],"tests":[{"name":"Output","stdin":"","expect":"[12, 20]\n['ant', 'cat']","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"def twice(operation, value):\n    return operation(operation(value))\n\n\ndef add_three(x):\n    return x + 3\n\n\nprint(twice(add_three, 1))\nprint(twice(lambda x: x * 10, 2))\nprint(twice(lambda s: s + \"!\", \"hey\"))\nprint(twice(abs, -5))\n","solution":"def twice(operation, value):\n    return operation(operation(value))\n\n\ndef add_three(x):\n    return x + 3\n\n\nprint(twice(add_three, 1))\nprint(twice(lambda x: x * 10, 2))\nprint(twice(lambda s: s + \"!\", \"hey\"))\nprint(twice(abs, -5))\n","hints":["`twice` calls `operation` on the value, then calls it again on the result.","`add_three` twice turns 1 into 4 and then 7. The second line multiplies by 10 two times, and the third adds an exclamation mark two times.","`abs(-5)` is 5, and `abs(5)` is still 5."],"tests":[{"name":"Output","stdin":"","expect":"7\n200\nhey!!\n5","hidden":false}],"require":[],"forbid":[],"lines":["7","200","hey!!","5"]},{"task":"Write a function `first_match(items, condition)` that returns the first item of the list for which the function `condition` returns `True`. If no item matches, it returns `None`. For example,\n\n```python\nprint(first_match([3, 8, 5, 12], lambda n: n > 6))\nprint(first_match([\"ant\", \"bee\"], lambda word: word.startswith(\"c\")))\n```\n\nshould print:\n\n```\n8\nNone\n```\n","kind":"code","seed":"def first_match(items, condition):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(first_match([3, 8, 5, 12], lambda n: n > 6))\n    print(first_match([\"ant\", \"bee\"], lambda word: word.startswith(\"c\")))\n","solution":"def first_match(items, condition):\n    for item in items:\n        if condition(item):\n            return item\n    return None\n\n\nif __name__ == \"__main__\":\n    print(first_match([3, 8, 5, 12], lambda n: n > 6))\n    print(first_match([\"ant\", \"bee\"], lambda word: word.startswith(\"c\")))\n","hints":["Go through the items with a `for` loop and call `condition(item)` for each one.","As soon as the condition returns `True`, return that item. The loop stops there.","If the loop ends without finding anything, return `None` after the loop."],"tests":[{"name":"Test 1","stdin":"","call":"print(first_match([3, 8, 5, 12], lambda n: n > 6))\nprint(first_match([\"ant\", \"bee\"], lambda word: word.startswith(\"c\")))\n","expect":"8\nNone","hidden":false},{"name":"Test 2","stdin":"","call":"def is_negative(number):\n    return number < 0\n\n\nprint(first_match([4, 0, -2, -7], is_negative))\nprint(first_match([], is_negative))\n","expect":"-2\nNone","hidden":true},{"name":"first_match([\"kiwi\", \"plum\", \"melon\", \"grape\"], lambda word: len(word) == 5)","stdin":"","call":"first_match([\"kiwi\", \"plum\", \"melon\", \"grape\"], lambda word: len(word) == 5)\n","expect":"'melon'","hidden":true,"returns":true}],"require":[],"forbid":[]}]}