Python learning log 10 - higher order functions and advanced applications

Posted by mrbaseball34 on Sun, 02 Jan 2022 19:11:40 +0100

Python learning log

Home page of RBHGO Welcome to pay attention

Warm tip: creation is not easy. If reprinted, indicate the source. Thank you for your cooperation~

catalogue

preface

Last time we shared functions, we also talked about the data types commonly used in Python. These types of variables can be used as parameters or return values of functions. Making good use of functions can also let us do more things. When we come into contact with functions, we must understand that when writing code, especially when developing commercial projects, we must consciously encapsulate relatively independent and recurring functions into functions, so that both ourselves and other members of the team can use these functions by calling functions. String is a very important data type. The common operations and methods of string need to be mastered, because in general commercial projects, there are more operations to deal with string than numerical value. The previous system has to share string knowledge character string , you can read it if you are interested.

Before we get down to business, I'll share a topic with you. First, let's talk about the stack structure

The function call will save the execution site of the current code through a data structure called "stack" in memory. After the function call, the previous execution site will be restored through this stack structure. Stack is a first in and last out data structure, which means that the earliest function on the stack will return last, and the last function on the stack will return first.

"""
Design a function to check the string (Arithmetic expression) Whether the brackets in match exactly.

algorithm:Loop through each character of the string and add the element to the stack if an open bracket is encountered;
If you encounter a right parenthesis, take an left parenthesis from the stack. If you can't get the left parenthesis, return it directly False;
If you can remove the left parenthesis, check whether they match;If not, return directly False;
If it matches, continue checking. After the loop traversal, check whether the stack is empty. If not, return False. 

Stack(stack) ---> FILO ---> There is a list if we limit the addition and deletion of elements to the end of the list
    - Add element: append() ---> Push 
    - Delete element: pop() ---> Out of stack
 queue(queue) ---> --->FIF0---> There is a list. If we limit it to adding elements at the tail and deleting elements at the head
    - Add element: append() ---> Join the team
    - Delete element: pop(0) ---> Out of the team

"""


def check(expression: str) -> bool:
    """
    Check that the parentheses in the string match exactly

    :param expression: expression
    :return: Bracket matching return True, Bracket mismatch return False
    """
    stack = []
    bdict = {'(': ')', '[':']', '{': '}'}
    for ch in expression:
        if ch in ('(', '[', '{'):
            stack.append(ch)
        elif ch in (')', ']', '}'):
            if len(stack) > 0:
                left = stack.pop()
                if bdict[left] != ch:
                    return False
            else:
                return False
    return len(stack) == 0


if __name__ == '__main__':
    print(check('{{{)(}{}}[][]])('))
    print(check('{(12 - 10 = 10)}'))

Get to the point

In the object-oriented world, everything is an object, so classes and functions are also objects. The parameters and return value of a function can be any type of object, which means that the function itself can also be used as the parameters or return value of a function, which is the so-called high-order function.

Python learning log Lesson 10 - higher order functions and advanced applications

Take the function as the parameter or return value of the function.

Functions in Python are first-class functions (first-class citizens):

  1. Functions can be arguments to functions
  2. Function can be used as the return value of a function
  3. Functions can be assigned directly to variables

(1). Recursive Method

According to the definition of higher-order function mentioned above, we first propose the case of function call itself.

  • The function call itself is a process as follows: Save site - > call function - > restore site
  • Each function has its own stack structure (about 512K-1M, which is not very large because it is required to be efficient). Saving the site is to save the whole stack structure

  • Conclusion: functions can be adjusted to others or themselves, but recursive calls must ensure rapid convergence (end as soon as possible, not unlimited calls), end calls under limited calls, and endless calls will consume the stack space sooner or later, leading to program crash.

def fac(num: int) -> int:
    """Factorial (recursive)"""
    # Limit (convergence) conditions to prevent stack space from running out
    if num == 0:
        return 1
    # Recursive call (in this case, call itself directly within the function)
    return num * fac(num - 1)

# __ name__ Is a hidden variable that represents the name of the current module (file)
if __name__ == '__main__':
    for i in range(1, 21):
        print(fac(i))

If you run the current code file directly through the Python interpreter, then__ name__ The value of is' '__ main__‘.

However, if the current module is imported in another module (file), then__ name__ The value of is the following module

When writing a function, doing so will avoid importing the module later. When running the program, the output of the imported module will be output together.

Tips:

  1. Recursion - > If a function directly or indirectly calls itself, this call is called recursion

  2. In PyCharm, tap main, then press tab key, if__ name__ == '__ main__' This paragraph will come straight out.

(2). High cohesion and low coupling

In addition to the feature that the function itself can also be used as the parameter or return value of the function, I think the function that achieves the ultimate goal of the code, high cohesion and low coupling, can also be called high-order function.

- **Low cohesion**: When you put`print`,`Binary operator`,`loop`,`input`Are reduced or even removed, and the code becomes easier to read and more effective
- **High coupling**: When the side effects in the function are cleared (e.g:The program is required to sort the output element subscripts. If you change the order of a piece of data itself, the subscripts are also changed)

Example 1 is as follows, where init_value represents the initial value of the operation, and op represents the binary operation function.

# Most binary operations are built in the operator
import operator


# Add an op parameter name -- > a function that implements binary operation (can do any binary operation)
# Add an init_ The value parameter name -- > is given to the initial value
def calculatec(init_value, op, *args, **kwargs):
    total = init_value
    for arg in args:
        if type(arg) in (int, float):
            total = op(total, arg)
    for value in kwargs.values():
        if type(value) in (int, float):
            total = op(total, value)
    return total


print(calculatec(0, operator.add, 11, 22, 33, 44))
print(calculatec(1, operator.mul, 11, 22, 33, 44))
print(calculatec(249, operator.sub, 11, 22, 33, 44))
print(calculatec(10000, operator.truediv, 11, 22, 33, 44))

Through the use of higher-order functions, calculatec functions are no longer coupled with addition and multiplication operations, so flexibility and universality will become stronger. It should be noted that there is a significant difference between using a function as a parameter and calling a function. Calling a function requires parentheses after the function name, while using a function as a parameter only requires the function name. There are many high-order functions in Python built-in functions. The map function we mentioned earlier is a high-order function. The map function can map the elements in the sequence.

Example 2 is as follows. When the function is opened, the list is fully sliced, which is equivalent to copying a code for sorting. The subsequent output index returns the subscript of the original list.

"""
Bubble sorting( Bubble Sort),It is a simple sorting algorithm in the field of computer science. It repeatedly visits the element column to be sorted, and compares two adjacent elements in turn, if the order (e.g. from large to small, first word)#3. The mother (from Z to A) exchanges them for mistakes. The work of visiting elements is repeated until no adjacent elements need to be exchanged, that is, the element column has been sorted.
"""

def bubble_sort(items, ascending=True):
    # Copy (full slice) the original list, and the program operation does not affect the original list
    # When designing a function, you must pay attention to the non side effects of the function (calling the function does not affect the caller)
    items = items[:]
    for i in range(1, len(items)):
        swapped = False
        for j in range(0, len(items) - i):
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if not swapped:
            break
        if not ascending:
            items = items[::-1]
    return items


if __name__ == '__main__':
    nums = [35, 96, 12, 78, 56, 64, 39, 80]
    print(nums)
    print(bubble_sort(nums))

(3).Lambda function

Lambda function - > the lambda function in Python has no name, so many people also call it an anonymous function, and it can be written in one sentence. The only expression is the return value of the function. When using higher-order functions, if the function itself as a parameter or return value is very simple, one line of code can be completed. At this time, we can use lambda functions.

# example02 - write a function that implements bubble sorting of list elements

def bubble_sort(items, ascending=True, gt=lambda x, y: x > y):
    """
    Bubble sort list elements

    :param items: List to sort
    :param ascending: Use ascending order
    :param gt: A function that compares the size of two elements
    :return: Returns the bubble sorted list
    """
    # Copy (full slice) the original list, and the program operation does not affect the original list
    # When designing a function, you must pay attention to the non side effects of the function (calling the function does not affect the caller)
    items = items[:]
    for i in range(1, len(items)):
        swapped = False
        for j in range(0, len(items) - i):
            if gt(items[j], items[j + 1]):
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if not swapped:
            break
    if not ascending:
        items = items[::-1]
    return items


if __name__ == '__main__':
    nums = [35, 96, 12, 78, 56, 64, 39, 80]
    letters = ['pink', 'ggbond', 'rainbow', 'zoo', 'internationalization']
    print(nums)
    print(bubble_sort(nums))
    print(bubble_sort(letters, gt=lambda x, y: len(x) > len(y), ascending=False))

Example 1 in (2) can also be implemented with Lambda

def calculatec(*args, init_value, op, **kwargs):
    total = init_value
    for arg in args:
        if type(arg) in (int, float):
            total = op(total, arg)
    for value in kwargs.values():
        if type(value) in (int, float):
            total = op(total, value)
    return total

# When defining a function, the parameters written in front of * are called positional parameters. When calling a function to pass parameters, you only need to be seated according to the number
# The parameters written after * are called named keyword parameters. When calling a function to pass parameters, they must be written in the form of "parameter name = parameter value"
print(calculatec(25, init_value=100, op=lambda x, y: x // y))

Many functions can be implemented in one line of code in Python. We can use Lambda functions to define these functions. Calling Lambda functions is the same as calling ordinary functions. The code is as follows.

import operator, functools

# One line of code defines the factorial function
fac = lambda num: functools.reduce(operator.mul, range(1, num + 1), 1)
# A line of code defines a function to judge prime numbers
is_prime = lambda x: x > 1 and all(map(lambda f: x % f, range(2, int(x ** 0.5) + 1)))

# Call Lambda function
print(fac(10))        			# Operation result: 3628800
print(is_prime(9))    			# Running result: False

Tip 1: the reduce function used above is a function in the functools module of Python standard library. It can realize the reduction of data. Generally, filter, map and reduce are the three key steps in data processing, and python standard library also provides support for these three operations.

Tip 2: the all function used above is a Python built-in function. If all Boolean values in the incoming sequence are True, the all function returns True, otherwise the all function returns False.

Little practice

Recursive implementation of Fibonacci sequence

def fib(n):
    """Implementation of Fibonacci sequence (recursive method)"""
    if n in (1, 2):
        return 1
    return fib(n - 1) + fib(n - 2)


if __name__ == '__main__':
    for i in range(1, 21):
        print(fib(i))

In fact, this is inefficient. It's better to write directly, but it's mainly to let you know the high-order application of recursion.

summary

For the recursive call of a function, we must pay attention to the convergence condition and recursive formula. Only when we find the recursive formula can we have the opportunity to use the recursive call, and the convergence condition determines when the recursion stops. Function calls save and restore the scene through the stack space in memory. The stack space is usually very small, so if recursion cannot converge quickly, it is likely to cause stack overflow errors, resulting in program crash. Functions in Python are also objects, so functions can be used as parameters and return values of functions, that is, we can use high-order functions in Python. When writing a program, try to ensure high cohesion and low coupling, no built-in coupling with Python, and ensure that the program has no side effects. If the function we want to define is very simple, with only one line of code and no name, we can write the function in the form of Lambda function (anonymous function).

Thank you for your study and company. Your praise and comments are the driving force for me to update

Topics: Python recursion