Python Functional Programming Guide (ii): Starting from a function

Source: Internet
Author: User
Tags abstract anonymous bool closure closure definition expression iterable zip

This article mainly introduces the Python Functional Programming Guide (ii): Starting from the function, this article explains the definition of a function, the use of function assignment, closures, as parameters, and so on, the need for friends can refer to the

2. Start with the function

2.1. Define a function

A summation function is defined as follows:

The code is as follows:

def add (x, y):

return x + y

The syntax details about parameters and return values can be referenced in other documents, which is skipped here.

You can use a lambda to define simple single line anonymous functions. The syntax for a lambda is:

The code is as follows:

Lambda args:expression

The syntax of a parameter (args) is the same as a normal function, while the value of an expression (expression) is the return value of an anonymous function call, and a lambda expression returns the anonymous function. If we give the anonymous function a name, it's like this:

The code is as follows:

Lambda_add = lambda x, y:x + y

This is exactly the same as the SUM function defined using DEF, which can be invoked as a function name using Lambda_add. However, the purpose of providing a lambda is to write anonymous functions that are occasionally simple, predictable and not modified. Although this style looks cool, it's not a good idea, especially if you need to expand it one day and never finish it with an expression. If you need to name a function at the outset, you should always use the DEF keyword.

2.2. Assigning values using functions

As a matter of fact you've already met, in the previous section we assigned the lambda expression to add. Similarly, a function defined with DEF can also be assigned a value that is equivalent to an alias for a function and can be invoked using this alias:

The code is as follows:

Add_a_number_to_another_one_by_using_plus_operator = Add

Print Add_a_number_to_another_one_by_using_plus_operator (1, 2)

Since functions can be referenced by variables, it is common practice to use functions as arguments and return values.

2.3. Closure of the package

Closures are a special kind of function. If a function is defined in the scope of another function, and the function references the local variable of the external function, then the function is a closure. The following code defines a closure:

The code is as follows:

def f ():

n = 1

def inner ():

Print n

Inner ()

n = ' x '

Inner ()

The function inner is defined in the scope of F, and the local variable n in f is used in inner, which constitutes a closure. The closure binds external variables, so the result of calling function f is to print 1 and ' X '. This is similar to the relationship between normal module functions and global variables defined in modules: Modifying external variables can affect values within the internal scope, while defining variables with the same name in an internal scope will obscure (hide) external variables.

If you need to modify a global variable in a function, you can use the keyword global to modify the variable name. There is no keyword in Python 2.x that provides support for modifying external variables in closures, and in 3.x the keyword nonlocal can do this:

The code is as follows:

#Python 3.x supports ' nonlocal '

def f ():

n = 1

def inner ():

nonlocal n

n = ' x '

Print (n)

Inner ()

Print (n)

The result of calling this function is to print 1 and ' X ', and if you have a Python 3.x interpreter, try to run it.

Because of the use of variables defined in vitro, it seems that closures violate functional style rules that are independent of external states. However, since closures are bound by local variables of external functions, and once left outside the scope of the function, these local variables will no longer be accessible externally; In addition, closures have an important feature that constructs a new closure each time it is executed to the closure definition. This feature makes the old closures bound variables not changed with the second call to the external function. So closures are not actually affected by the external state, fully compliant with functional style requirements. (Here's a special case, in Python 3.x, if you have two closures defined in the same scope, they can interact with each other because you can modify external variables.) )

While closures can only play its real power as a parameter and return value, the support of closures still greatly improves productivity.

2.4. As a parameter

If you are familiar with OOP template method patterns, believe you can quickly learn to pass functions as parameters. The two are generally consistent, but here we are passing the function itself and not the object that implements the interface.

Let's start by adding a hot warm up to the SUM function defined above:

The code is as follows:

Print add (' Triangular tree ', ' Arctic ')

Unlike the addition operator, you must be surprised that the answer is ' trigonometric functions '. This is a built-in egg ... bazinga!

Anyway Our customers have a list of 0 to 4:

The code is as follows:

LST = range (5) #[0, 1, 2, 3, 4]

Although we gave him an adder in the previous section, he still frets about how to compute the sum of all the elements of the list. Of course, this is a very relaxing task for us:

The code is as follows:

Amount = 0

For num in LST:

Amount = Add (amount, num)

This is a typical instruction style code, there is no problem, certainly can get the correct results. Now, let's try refactoring with a functional style.

The first thing you can foresee is that the summation is very common, and if we abstract this action into a separate function and then need to sum another list, we don't have to write it again:

The code is as follows:

def sum_ (LST):

Amount = 0

For num in LST:

Amount = Add (amount, num)

return amount

Print Sum_ (LST)

can still continue. The SUM_ function defines such a process:

1. Use the initial value to add to the first element of the list;

2. Add the result of the last addition to the next element of the list;

3. Repeat the second step until there are no more elements in the list;

4. Return the result of the last addition.

If you need to ask for a product now, we can write a similar process--just add the addition to multiply it:

The code is as follows:

def multiply (LST):

Product = 1

For num in LST:

Product = product * num

Return product

In addition to the initial value replaced by 1 and function add replaced by the multiplication operator, all the other code is redundant. Why don't we just abstract the process and pass the addition, multiplication, or other functions as arguments?

The code is as follows:

Def reduce_ (function, LST, initial):

result = Initial

For num in LST:

result = function (result, num)

return result

Print Reduce_ (add, LST, 0)

Now, to calculate the Chuyang product, you can do this:

The code is as follows:

Print Reduce_ (lambda x, y:x * y, LST, 1)

So, what should you do if you want to use Reduce_ to find the maximum value in the list? Please think for yourself:

Although there are design patterns such as template methods, such complexity tends to make people more willing to write loops around. The function as an argument completely avoids the complexity of the template method.

Python has a built-in function, reduce, to fully implement and extend the functionality of the Reduce_. The section later in this article contains an introduction to useful built-in functions. Note that our goal is to have no loops, and using a function substitution loop is the most obvious feature of a functional style that distinguishes it from a command style.

* A functional language built on a class C language like Python, because the language itself provides the ability to write looping code, built-in functions, while providing functional programming interfaces, are generally implemented internally or in loops. Similarly, if you find that the built-in function does not meet your cyclic requirements, you might as well encapsulate it and provide an interface.

2.5. As a return value

Returning a function usually needs to be used with closures (that is, to return a closure) in order to be powerful. Let's look at the definition of a function:

The code is as follows:

Def map_ (function, LST):

result = []

For item in LST:

Result.append (function (item))

return result

Function Map_ encapsulates one of the most common iterations: Call a function on each element in the list. MAP_ requires a function argument and returns the result of each call in a list. This is a directive approach, and when you know the list comprehension, there will be a better implementation.

Here we'll skip the MAP_ implementation and focus on its functionality. For the LST in the previous section, you may find that the final product result is always 0, because LST contains 0. To make the result look large enough, we use MAP_ to add 1 to each element in the LST:

The code is as follows:

LST = Map_ (lambda x:add (1, x), LST)

Print Reduce_ (lambda x, y:x * y, LST, 1)

The answer is 120, which is far from big enough. Again:

The code is as follows:

LST = Map_ (lambda x:add (x), LST)

Print Reduce_ (lambda x, y:x * y, LST, 1)

In fact, I really didn't think the answer would be 360360, I swear I didn't accept Zhou 祎 any benefit.

Now look back at the two lambda expressions we've written: The similarity is over 90%, and you can definitely use plagiarism to describe it. And the problem is not plagiarism, is written more than a lot of characters have wood? If you have a function that generates an addition function based on the left-hand operand you specify, it will work like this:

The code is as follows:

LST = MAP_ (add_to (), LST) #add_to (10) Returns a function that takes a parameter and adds 10 to return

It would be much more comfortable to write. Here is the implementation of the function add_to:

The code is as follows:

def add_to (n):

return Lambda X:add (n, x)

By specifying a number of arguments for a function that already exists, a new function is generated that only needs to pass in the remaining unspecified parameters to achieve the full functionality of the original function, which is called a partial function. Python's built-in Functools module provides a function partial that can generate partial functions for any function:

The code is as follows:

Functools.partial (func[, *args][, **keywords])

You need to specify a function to generate a partial function, specify a number of arguments or named arguments, and then partial will return the partial function, but strictly speaking, partial returns not a function, but rather an object that can be called directly like a function, which, of course, does not affect its functionality.

Another special example is the adorner. Adorners are used to enhance or even simply change the function of the original function, I have written a document to introduce the adorner, address here: http://www.jb51.net/article/59867.htm.

* digression, in the case of this feature, in some other functional languages (such as Scala) you can use a technology called currying (for example) to achieve more elegance. It is the technique of transforming a function that accepts multiple parameters into a function that accepts a single parameter (the first parameter of the original function), and returns a new function that accepts the remaining parameters and returns the result. As shown in the pseudocode below:

The code is as follows:

#不是真实的代码

def add (x) (y): #柯里化

return x + y

LST = MAP_ (add), LST)

By add_to the Add function, add accepts the first argument x and returns a function that accepts the second argument y, which is called exactly the same as the previous one (returns x + y) and no longer needs to define the add_to. Does it look more refreshing? Unfortunately, Python does not support Gerty.

2.6. Partial built-in function introduction

Reduce (function, iterable[, initializer])

The main function of this function is the same as the reduce_ we have defined. Need to add two points:

Its second argument can be any object that can be iterated (the object that implements the __iter__ () method);

If you do not specify a third argument, the first call to function will use the first two elements of iterable as parameters.

The combination of reduce and some common functions is the built-in function listed below:

The code is as follows:

All (iterable) = = reduce (lambda x, Y:bool (x and Y), iterable)

Any (iterable) = = reduce (lambda x, Y:bool (x or y), iterable)

Max (iterable[, args ...) [, Key]) = = Reduce (lambda x, y:x if key (x) > key (y) Else y, Iterable_and_args)

Min (iterable[, args ...) [, Key]) = = Reduce (lambda x, y:x if key (x) < key (y) Else y, Iterable_and_args)

Sum (iterable[, start)) = = reduce (lambda x, y:x + y, iterable, start)

Map (function, iterable, ...)

The main function of this function is the same as the MAP_ we have defined. One thing to add:

The map can also accept multiple iterable as parameters, and in the nth call function, it will use Iterable1[n], iterable2[n], ... As a parameter.

Filter (function, iterable)

The function of this function is to filter out all elements in iterable that return TRUE or bool (return value) to true when invoking function as parameters themselves, and return with the list, in the same order as the My_filter function in the first article of the series.

Zip (Iterable1, iterable2, ...)

This function returns a list, each element is a tuple, containing (Iterable1[n], iterable2[n], ...).

For example: Zip ([1, 2], [3, 4])--> [(1, 3), (2, 4)]

If the length of the argument is inconsistent, it ends at the end of the shortest sequence, and if no argument is supplied, an empty list is returned.

In addition, you can use the functools.partial () mentioned in section 2.5 of this article to create commonly used partial functions for these built-in functions.

In addition, there is a module named functional on the PyPI, which provides additional interesting functions in addition to these built-in functions. However, due to the use of the situation is not much, and need additional installation, in this article is not introduced. But I still recommend you to download this module's pure Python implementation of the source code look, open thinking. The functions inside are very short, the source file is only 300 lines in total, the address is here: http://pypi.python.org/pypi/functional

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.