Home > front end >  How can I write my own function that accepts and uses a function as a parameter?
How can I write my own function that accepts and uses a function as a parameter?

Time:05-23

I have seen several examples, in the standard library and major third-party libraries, of functions (and methods) that accept a function as input.

For example, consider the apply method of Pandas DataFrames. The documentation of the method suggests you can pass another function like sum() or numpy.sqrt() into the function, like apply(sum) or apply(numpy.sqrt).

Similarly, the standard library sorted function explicitly documents that

key specifies a function of one argument that is used to extract a comparison key from each element in iterable (for example, key=str.lower).

How can I write my own function that works this way, accepting a function as one of the inputs?

CodePudding user response:

You do this the same way that you would write the function to accept anything else. Python's def statements don't require any type specification:

def example(parameter):
    pass

You can pass any object; functions are objects; therefore, you can pass functions:

def argument():
    print("This message won't be printed this time, but keep reading")

example(argument)

To make it possible to pass the function as an argument, you do exactly nothing.

The same applies, mutatis mutandis, to methods as well as ordinary functions:

class Example:
    def method(self, parameter):
        pass

Example().method(argument)

"But how do I use it inside the function?"

Unless you are doing something really unusual (at a research level way beyond this question), the only really interesting thing to do with a function - aside from passing it around like this - is to call it.

You call a function by getting the function, then writing the function-call syntax after it (the argument list between parentheses). Functions are objects; you get objects by evaluating an expression; therefore you get functions by evaluating an expression (as long as it actually does evaluate to a function).

Normally, that expression is... the function's name, looked up in the global namespace (as in the above examples). But just as is the case with any other object, you can do it other ways.

In particular, you can give the value other names - for example, by passing it as a parameter. That's what happens when you call a function: the function uses its parameter name as a name for whatever was passed as an argument.

Including if that's another function.

Inside the called function, then, you call the passed function by naming it - with the parameter name - and then using the normal function call syntax.

def example(parameter):
    parameter()

Now the (misleading) message is printed.

More complex expressions are possible. One common pattern is to look them up in a dictionary (although 3.10's match... case construct makes this slightly less useful). Another way is to compile code dynamically (there are a lot of approaches for this; all of them are at least somewhat dangerous, so I will not name or show them here. People with a legitimate use for this, also have the skill to do the necessary research.)

CodePudding user response:

A function accepting other functions as argument or returning functions is called higher-order function.

So Panda's apply() is a higher-order function. It accepts another function like e.g. sum and calls or invokes it internally as sum(args).

To define a higher-order function that accepts a function as argument use a signature as with common functions.

In the examples below this will be def md_heading(phrase):.

How to call the functional parameter (without arguments)

See how to invoke the argument which is expected to be a function:

def md_heading(phrase):
    return "# "   phrase()

Note:

  • The parameter was named like a variable name here - not with the explicit notation of requiring a function like in Panda's apply(func).
  • Still this parameter phrase is expected to be a function-reference because it will be invoked using parentheses (without argument).
  • md_heading() is the wrapper function, phrase the functional parameter.

Passing a literal

Now try what happens when passing a string literal like `'Hello World' as argument.

result = md_heading('Hello World')  # this would pass it in, then try to call it .. and ?
print(result)

The invocation of the string passed as argument will raise an error. In exactly that statement return "# " phrase() as:

TypeError: 'str' object is not callable

Passing a function (reference) as argument

Now you should pass a function as argument, but just as reference (without parentheses):

def greeting():
   return 'Hi'

result = md_heading(greeting)
print(result)

Prints: Hi

Passing a lambda as argument

Or you can pass a lambda as argument:

result = md_heading(lambda: "Hello!")
print(result)

Prints: 'Hello!

Note: The lambda must not have a positional argument. This the closes to passing a constant, like the string from the beginning.

No (required) parameters when passing lambdas

When we define the lambda with a positional argument like lambda name: "Hello " name here, it will raise: TypeError: <lambda>() missing 1 required positional argument: 'name' because in our higher-order function it is invoked without argument, just as phrase().

CodePudding user response:

What's happening because you give in function apply only link in memory for function sum. And in your apply function this link wiil be called.

def apply(some_func):
    result = some_func(28, 79)
    return result

This function returns you sum 28 and 79 (107).

  • Related