Are you still programming imperatively? Python functional programming makes your code more elegant!

Python supports functional programming, a programming paradigm that treats computer programs as compositions of mathematical functions.

Article Directory

1. Lambda expression

Definition of lambda expression

Application scenarios of lambda expressions

Limitations of lambda expressions

Advanced usage of lambda expressions

Second, Python's higher-order functions

Definition of Higher Order Functions

Commonly used higher-order functions

function as parameter

function as return value

3. Functools module

Introduction to the functools module

partial() function

lru_cache() function

wraps() function

cmp_to_key() function

4. Python generator

generator definition

How generators work

Advantages of generators

Application Scenarios of Generators

Notes on generators

5. Python decorator

Definition of decorator

How decorators work

Application scenarios of decorators

Note on decorators

6. Python list comprehension and dictionary comprehension

Definition of list comprehension

How List Comprehensions Work

Application scenarios of list comprehension

dictionary comprehension definition

How Dictionary Comprehensions Work

Application scenarios of dictionary comprehension

Notes on List Comprehensions and Dictionary Comprehensions

7. Functional Programming Libraries in Python

functools

itertools

toolz

fn.py

PyMonad


1. Lambda expression

Lambda expressions are an important feature in the Python language, which can be used to define simple anonymous functions. Lambda expressions are commonly used in scenarios such as higher-order functions, list comprehensions, dictionary comprehensions, and decorators. It should be noted that lambda expressions are usually only suitable for simple function definitions, and complex function definitions usually need to be defined using def statements.

Definition of lambda expression

A lambda expression is an anonymous function that defines a simple function where a function is expected to be used. The syntax of a lambda expression is as follows:

lambda arguments: expression

Among them, arguments represents the parameter list of the function, which can have multiple parameters separated by commas; expression represents the return value expression of the function, which can be any expression.

Here is a sample code using lambda expressions:

my_list = [1, 2, 3, 4, 5]
result = map(lambda x: x*2, my_list)
print(list(result))

In the above code, we defined an anonymous function using lambda expression and passed it to the map() function.

Application scenarios of lambda expressions

Lambda expressions are often used to define simple functions for one-time use. For example, when using higher-order functions such as map(), reduce(), and filter(), we can use lambda expressions to define functions for mapping, reducing, and filtering.

Here is a sample code using lambda expressions:

my_list = [1, 2, 3, 4, 5]
result = filter(lambda x: x%2==0, my_list)
print(list(result))

In the above code, we defined a function using lambda expression to filter the even elements in the list and passed it to the filter() function.

Limitations of lambda expressions

Lambda expressions are usually only suitable for simple function definitions, and complex function definitions usually need to be defined using def statements. A lambda expression can contain only one expression, and the result of that expression will be the return value of the function. Statement or assignment operators cannot be used in lambda expressions.

Here is a sample code that cannot use lambda expressions:

def my_function():
    print("My function")
    return 1

my_lambda = lambda: (print("My lambda"), 1)[1]
result = my_lambda()
print(result)

In the above code, we defined a function my_function(), which contains a print statement and a return statement. We tried using lambda expressions to define the same function, but since lambda expressions can only contain one expression, we used a ternary expression to simulate the return statement.

Advanced usage of lambda expressions

Lambda expressions can be used in conjunction with other Python language features, such as list comprehensions, dictionary comprehensions, and decorators.

Here is an example code using lambda expressions and list comprehensions:

my_list = [1, 2, 3, 4, 5]
result = [(lambda x: x*2)(x) for x in my_list]
print(result)

In the code above, we use lambda expressions and list comprehensions to create a new list that contains twice the number of elements in the original list.

Second, Python's higher-order functions

Higher-order functions are an important concept in Python functional programming, which can make the code more flexible and reduce code duplication. Commonly used higher-order functions in Python include map(), reduce(), filter(), etc. Functions can be passed as arguments to other functions, or returned to the caller as return values. It should be noted that high-order functions usually need to use lambda expressions to define functions, and lambda expressions can be used to define simple anonymous functions.

Definition of Higher Order Functions

A higher-order function is a function that can accept a function as an argument or return a function as a result. Some higher-order functions are built into Python, including map(), reduce(), filter(), etc.

Here is a sample code using the map() function:

my_list = [1, 2, 3, 4, 5]
result = map(lambda x: x*2, my_list)
print(list(result))

In the above code, we are multiplying the elements of a list by 2 using the map() function and converting the result into a list using the list() function.

Commonly used higher-order functions

Commonly used higher-order functions in Python include:

  • The map() function: accepts a function and a sequence as parameters, applies the function to each element in the sequence, and returns a new sequence.

Here is a sample code using the map() function:

my_list = [1, 2, 3, 4, 5]
result = map(lambda x: x*2, my_list)
print(list(result))

In the above code, we are multiplying the elements of a list by 2 using the map() function and converting the result into a list using the list() function.

  • reduce() function: accepts a function and a sequence as parameters, and uses the function to reduce the elements in the sequence to a single value.

Here is an example code using the reduce() function:

from functools import reduce

my_list = [1, 2, 3, 4, 5]
result = reduce(lambda x, y: x+y, my_list)
print(result)

In the above code, we use the reduce() function to accumulate the elements in a list and return the accumulated result.

  • filter() function: accepts a function and a sequence as parameters, uses the function to filter out the eligible elements in the sequence, and returns a new sequence.

Here is a sample code using the filter() function:

my_list = [1, 2, 3, 4, 5]
result = filter(lambda x: x%2==0, my_list)
print(list(result))

In the above code, we have filtered the even elements in a list using the filter() function and converted the result into a list using the list() function.

function as parameter

In Python, functions can be passed as arguments to other functions. This usage can make the code more flexible and reduce code duplication.

Here is a sample code that uses a function as an argument:

def my_function(x):
    return x*2

def apply_function(f, lst):
    return [f(x) for x in lst]

my_list = [1, 2, 3, 4, 5]
result = apply_function(my_function, my_list)
print(result)

In the above code, we defined a function my_function() to multiply a number by 2. Then we define a function apply_function() that takes a function and a list as parameters, applies the function to each element in the list, and returns a new list. Finally, we pass the my_function() function and the my_list list to the apply_function() function and save its result in the result variable.

function as return value

In Python, functions can also be returned to the caller as return values. This usage can make the code more flexible, and can return different functions according to different situations.

Here is an example code that uses a function as a return value:

def get_math_function(operation):
    if operation == '+':
        return lambda x, y: x+y
    elif operation == '-':
        return lambda x, y: x-y
    elif operation == '*':
        return lambda x, y: x*y
    elif operation == '/':
        return lambda x, y: x/y

my_function = get_math_function('*')
result = my_function(2, 3)
print(result)

In the above code, we have defined a function get_math_function() which returns different functions depending on the parameters. Then we call the get_math_function() function, passing the parameter '*', and save the returned function into the my_function variable. Finally, we call the my_function() function, passing 2 and 3 as parameters, and save the result in the result variable.

3. Functools module

The functools module is a module in the Python standard library that provides some higher-order functions and functional programming tools. This module can be used to implement functions such as function currying, partial functions, and caching. Commonly used functions in the functools module include partial() function, lru_cache() function, wraps() function, cmp_to_key() function, etc. It should be noted that the functions in the functools module usually need to be used together with other functions to achieve more complex functions.

Introduction to the functools module

The functools module is a module in the Python standard library that provides some higher-order functions and functional programming tools. This module can be used to implement functions such as function currying, partial functions, and caching.

Here is an example code using the functools module:

import functools

def my_function(x, y):
    return x*y

my_partial = functools.partial(my_function, y=2)
result = my_partial(3)
print(result)

In the above code, we use the partial() function in the functools module to create a partial function my_partial, which fixes the second parameter of the my_function function to 2. Then we call the my_partial() function, passing 3 as the first parameter of the my_function() function, and save the result in the result variable.

partial() function

The partial() function is a function in the functools module for creating partial functions. A partial function refers to fixing some parameters of a function and returning a new function.

Here is a sample code using the partial() function:

import functools

def my_function(x, y):
    return x*y

my_partial = functools.partial(my_function, y=2)
result = my_partial(3)
print(result)

In the above code, we use the partial() function to create a partial function my_partial, which fixes the second parameter of the my_function function to 2. Then we call the my_partial() function, passing 3 as the first parameter of the my_function() function, and save the result in the result variable.

lru_cache() function

The lru_cache() function is a function in the functools module, which is used to create a cache, which can cache the result of the function call and avoid repeated calculations.

The following is a sample code using the lru_cache() function:

import functools

@functools.lru_cache()
def my_function(x):
    print("Calculating...")
    return x*x

result = my_function(2)
print(result)

result = my_function(2)
print(result)

In the above code, we use the lru_cache() function to create a cache to cache the result of the my_function() function call. Then we call the my_function() function, passing 2 as an argument, and save the result in the result variable. When the my_function() function is called for the second time, since it has been calculated before, the result is directly obtained from the cache and no calculation is performed.

wraps() function

The wraps() function is a function in the functools module, which is used to define a decorator, which is used to copy the __name__, doc, __module__ and other attributes of the decorated function to the decorator function.

Here is a sample code using the wraps() function:

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Before...")
        result = func(*args, **kwargs)
        print("After...")
        return result
    return wrapper

@my_decorator
def my_function(x):
    """
    This is my function.
    """
    return x*x

result = my_function(2)
print(result)
print(my_function.__name__)
print(my_function.__doc__)

In the above code, we define a decorator my_decorator, which is used to print some information before and after the execution of the decorated function. Then we use the wraps() function to copy the properties of the decorated function into the decorator function. Finally, we decorate a function my_function with my_decorator and call the function.

cmp_to_key() function

The cmp_to_key() function is a function in the functools module that converts an old-style comparison function into a key function. In Python 2.x, the comparison function is used to compare the size of two elements; in Python 3.x, the comparison function has been removed and replaced by the key function.

The following is a sample code using the cmp_to_key() function:

import functools

def my_compare(x, y):
    if x < y:
        return -1
    elif x > y:
        return 1
    else:
        return 0

my_list = [5, 3, 2, 8, 7]
my_key = functools.cmp_to_key(my_compare)
my_list.sort(key=my_key)
print(my_list)

In the above code, we define an old-style comparison function my_compare to compare the size of two elements. We then convert this function to the key function my_key using the cmp_to_key() function. Finally, we sort my_list using the my_list.sort() function, passing my_key as a parameter.

4. Python generator

A generator is a special kind of iterator that can generate data dynamically and can be created through a function or a generator expression. Generators have the advantages of lazy computing, infinite sequences, stream processing, etc., and can be used to process large amounts of data, generate infinite sequences, implement coroutines and asynchronous programming, etc. It should be noted that the generator can only iterate once, cannot use slice operations, and needs to be closed in time.

generator definition

A generator is a special kind of iterator that dynamically generates data in a loop instead of generating all the data at the beginning. Generators can be created using functions or generator expressions.

Here is an example code for creating a generator using a generator expression:

my_generator = (x*x for x in range(10))
print(list(my_generator))

In the above code, we use generator expression to create a generator my_generator that can dynamically generate squares from 0 to 9 and convert it to a list using list() function.

How generators work

The working principle of the generator can be simply described as: every time the generator's __next__() method is called, it will execute to the next yield statement and return the value of the statement. When all the yield statements are executed, the generator will automatically throw a StopIteration exception, indicating the end of the iteration.

Here is an example code for creating a generator using the yield statement:

def my_generator():
    for i in range(10):
        yield i*i

gen = my_generator()
print(list(gen))

In the above code, we have created a generator inside the function using the yield statement. Each time the generator's __next__() method is called, it executes to the next yield statement and returns the value of that statement. Finally, we convert the generator to a list using the list() function.

Advantages of generators

Generators have the following advantages:

  • Lazy calculation: The generator does not generate all the data at the beginning, but only generates data when needed, which can save a lot of memory space.
  • Infinite sequence: Generators can be used to generate infinite sequences, such as Fibonacci sequence, prime number sequence, etc.
  • Can be used for streaming: The generator can be used for streaming large amounts of data, such as reading large files, network data, etc.

Here's an example code that uses generators to handle large files:

def read_file(file_path):
    with open(file_path) as f:
        for line in f:
            yield line.strip()

for line in read_file("large_file.txt"):
    process(line)

In the above code, we define a generator read_file(), which is used to read large files and return one line of data each time. Then we use a for loop to traverse the generator and process each row of data.

Application Scenarios of Generators

Generators can be used in the following scenarios:

  • Handle large amounts of data, such as large files, network data, etc.
  • Generate infinite sequences such as Fibonacci numbers, prime numbers, etc.
  • Implement coroutines and asynchronous programming, such as using the asyncio library to implement asynchronous IO operations.
  • Generators can also be used to implement the pipe and filter patterns, for example using generators to implement Unix pipes.

Notes on generators

Although generators have many advantages, they also need to pay attention to the following:

  • The generator can only iterate once: The generator can only iterate once, because a StopIteration exception is automatically thrown after the iteration is complete.
  • Generators cannot use slice operations: Since generators are evaluated lazily, slice operations cannot be used, otherwise the generator will terminate prematurely.
  • The generator needs to be closed in time: The generator needs to be closed in time after use, otherwise it may cause problems such as resource leaks and memory leaks.

5. Python decorator

A decorator is a syntactic sugar of the Python language used to modify or enhance the functionality of a function or class. The decorator itself is a function that receives a function as a parameter and returns a new function. The new function performs some additional operations before and after calling the original function, and finally returns the return value of the original function. Decorators can be used to record logs, timers, caches, permission control, retry mechanisms and other scenarios. When using a decorator, you need to pay attention to the definition and calling rules of the function, the parameters of the decorator, nested use, and retaining the meta-information of the original function.

Definition of decorator

A decorator is a syntactic sugar of the Python language used to modify or enhance the functionality of a function or class. Decorators can dynamically add additional functionality to the original function or class without modifying them.

The following is a sample code that uses decorators to enhance the functionality of functions:

def my_decorator(func):
    def wrapper():
        print("Before function call")
        func()
        print("After function call")
    return wrapper

@my_decorator
def my_function():
    print("Inside function")

my_function()

In the above code, we define a decorator my_decorator to print some information before and after the function call. Then we use @my_decorator syntactic sugar to apply the decorator to the function my_function.

How decorators work

The working principle of the decorator can be simply described as: the decorator itself is a function, it receives a function as a parameter, and then returns a new function, the new function performs some additional operations before and after calling the original function, and finally returns the original function return value.

The following is a sample code that uses decorators to enhance the functionality of functions:

def my_decorator(func):
    def wrapper():
        print("Before function call")
        func()
        print("After function call")
    return wrapper

@my_decorator
def my_function():
    print("Inside function")

my_function()

In the above code, the decorator my_decorator takes a function as an argument and returns a new function wrapper. When the my_function() function is called, the wrapper() function is actually called, which prints some information before and after calling the original function, and executes the original function. Finally, the wrapper() function returns the return value of the original function.

Application scenarios of decorators

Decorators can be used in the following scenarios:

  • Logging: You can use the decorator to record the call log of the function, such as recording the parameters, return value, execution time, etc. of the function.
  • Timer: A timer can be implemented using a decorator to calculate the execution time of a function.
  • Cache: A decorator can be used to implement a cache to cache the results of function calls to avoid repeated calculations.
  • Access control: Decorators can be used to implement an access control, restricting only specific users or roles to call functions.
  • Retry mechanism: Decorators can be used to implement a retry mechanism. When a function call fails, it will automatically retry multiple times.

The following is a sample code that uses decorators to implement caching:

import functools

def cache(func):
    cache_dict = {}
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        key = args + tuple(kwargs.items())
        if key not in cache_dict:
            cache_dict[key] = func(*args, **kwargs)
        return cache_dict[key]
    return wrapper

@cache
def my_function(x, y):
    print("Calculating...")
    return x*y

print(my_function(2, 3))
print(my_function(2, 3))

In the above code, we define a cache decorator to cache the result of the function call. Then we apply the decorator to the function my_function using @cache syntactic sugar.

Note on decorators

There are a few things to keep in mind when using decorators:

  • The decorator itself is also a function, so it needs to follow the definition and calling rules of the function.
  • A decorator can receive parameters, but it needs to define another layer of functions inside the decorator to receive parameters.
  • Decorators can be nested, but you need to pay attention to the order of function calls.
  • Decorators can use the functools.wraps() function to preserve the meta-information of the original function, such as function name, documentation string, etc.

6. Python list comprehension and dictionary comprehension

List comprehensions and dictionary comprehensions are a concise and powerful Python syntax for generating new lists and dictionaries. They both work by iterating over an iterable object through a for loop, operating on each element, and adding the results to a new list or dictionary. They can be used to filter data, transform data, generate new lists or dictionaries, and more. When using list comprehension and dictionary comprehension, you need to pay attention to the readability of the code, the position and condition of the if statement, and the order of the for statement.

Definition of list comprehension

List comprehensions are a concise and powerful Python syntax for generating new lists. List comprehensions can often perform complex list operations with a single line of code.

Here is an example code that generates a new list using a list comprehension:

my_list = [x*x for x in range(10)]
print(my_list)

In the code above, we use a list comprehension to generate a new list that contains squares from 0 to 9.

How List Comprehensions Work

The working principle of the list comprehension can be simply described as: iterate through an iterable object through a for loop, operate on each element, and add the result to a new list.

Here is an example code that generates a new list using a list comprehension:

my_list = [x*x for x in range(10)]
print(my_list)

In the above code, the for loop iterates over the integers from 0 to 9, squares each integer, and adds the result to a new list.

Application scenarios of list comprehension

List comprehensions can be used in the following scenarios:

  • Filter data: You can use list comprehensions to filter data in lists based on conditions.
  • Transforming data: You can use list comprehensions to transform data in lists, such as converting a list of strings to a list of integers.
  • Generate new lists: You can use list comprehensions to generate new lists, such as generating Fibonacci sequence, prime number sequence, etc.

Here is an example code that converts a list of strings to integers using a list comprehension:

my_list = ["1", "2", "3", "4", "5"]
new_list = [int(x) for x in my_list]
print(new_list)

In the above code, we use a list comprehension to convert the elements in the list of strings my_list to integers and store the result in a new list new_list.

dictionary comprehension definition

Dictionary comprehensions are a concise and powerful Python syntax for generating new dictionaries. Dictionary comprehensions can usually perform complex dictionary operations with one line of code.

Here is an example code that generates a new dictionary using a dictionary comprehension:

my_dict = {x: x*x for x in range(10)}
print(my_dict)

In the code above, we use a dictionary comprehension to generate a new dictionary that contains integers from 0 to 9 and their squares.

How Dictionary Comprehensions Work

The working principle of dictionary comprehension can be simply described as: Iterate over an iterable object through a for loop, operate on each element, and add the result to a new dictionary.

Here is an example code that generates a new dictionary using a dictionary comprehension:

my_dict = {x: x*x for x in range(10)}
print(my_dict)

In the code above, the for loop iterates over the integers from 0 to 9, squares each integer, and adds the result to a new dictionary.

Application scenarios of dictionary comprehension

Dictionary comprehensions can be used in the following scenarios:

  • Filter data: You can use dictionary comprehensions to filter data in dictionaries based on conditions.
  • Converting data: You can use dictionary comprehensions to convert data in a dictionary, such as converting string values ​​in a dictionary to integer values.
  • Generating new dictionaries: You can use dictionary comprehension to generate new dictionaries, such as converting a list to a dictionary, where the elements of the list are used as the keys of the dictionary, and the elements in another iterable object are used as the values ​​​​of the dictionary.

Here is an example code that uses dictionary comprehensions to convert string values ​​in a dictionary to integer values:

my_dict = {"a": "1", "b": "2", "c": "3", "d": "4", "e": "5"}
new_dict = {k: int(v) for k, v in my_dict.items()}
print(new_dict)

In the above code, we use dictionary comprehensions to convert the string values ​​in the dictionary my_dict to integer values ​​and store the result in a new dictionary new_dict.

Notes on List Comprehensions and Dictionary Comprehensions

Note the following when using list comprehensions and dictionary comprehensions:

  • List comprehensions and dictionary comprehensions can be nested, but you need to pay attention to the readability of the code.
  • List comprehensions and dictionary derivations can be filtered using if statements, and you need to pay attention to the position and conditions of the if statements.
  • List comprehension and dictionary comprehension can be nested using multiple for statements, and attention should be paid to the order of the for statements.

7. Functional Programming Libraries in Python

There are many functional programming libraries in Python, and each library has its own characteristics and applicable scenarios. Among them, functools and itertools are part of the Python standard library, which can be directly imported and used, and the functions are relatively simple; while toolz, fn.py and PyMonad need to be installed, providing some advanced functional programming functions, suitable for some complex functional programming scenarios . When using a functional programming library, it is necessary to select an appropriate library according to the specific scenario to achieve the best programming effect.

The following are some commonly used functional programming libraries and their functions, usage differences, usage scenarios, advantages and disadvantages, etc.:

functools

  • Functional role: Provides some high-order functions, such as partial, reduce, wraps, etc., which can easily operate functions.
  • Differences in use: functools is part of the Python standard library and can be directly imported and used without installation.
  • Usage scenarios: It can be used in scenarios such as currying of functions, decorators of functions, and preservation of meta-information of functions.
  • Advantages: No installation required, easy to use, rich in functions.
  • Disadvantages: The function is relatively simple, and it is not suitable for some complex functional programming scenarios.

itertools

  • Functional role: Provides some iterator functions, such as product, permutations, combinations, etc., which can easily generate iterators.
  • Differences in use: itertools is part of the Python standard library and can be directly imported and used without installation.
  • Usage scenarios: It can be used to generate permutations and combinations, Cartesian products, loop iterations and other scenarios.
  • Advantages: No installation required, easy to use, rich in functions.
  • Disadvantages: Only some iterator functions are provided, which is not suitable for some complex functional programming scenarios.

toolz

  • Functional role: Provides some high-order functions, such as curry, compose, pipe, etc., which can easily operate functions.
  • Differences in use: toolz needs to be installed, and can be installed using the pip command, such as pip install toolz.
  • Usage scenarios: It can be used in scenarios such as currying of functions, combination of functions, and lazy calculation.
  • Advantages: Provides some advanced functional programming functions, suitable for some complex functional programming scenarios.
  • Disadvantages: It needs to be installed, and it is a little complicated to use.

fn.py

  • Functional role: Provides some high-order functions, such as curry, compose, zip_with, etc., which can easily operate functions.
  • Use difference: fn.py needs to be installed, you can use the pip command to install, such as pip install fn.
  • Usage scenarios: It can be used in scenarios such as currying of functions, combination of functions, lazy calculations, and lazy sequences.
  • Advantages: Provides some advanced functional programming functions, suitable for some complex functional programming scenarios.
  • Disadvantages: It needs to be installed, and it is a little complicated to use.

PyMonad

  • Functional role: Provide some basic monadic types, such as Maybe, Either, State, etc., which can easily realize the monadic pattern.
  • Use difference: PyMonad needs to be installed, you can use the pip command to install, such as pip install PyMonad.
  • Usage scenarios: It can be used to implement scenarios such as monadic patterns, exception handling in functional programming, and state management.
  • Advantages: Provides some basic monadic types to facilitate the implementation of monadic patterns.
  • Disadvantages: The function is relatively simple, and it is not suitable for some complex functional programming scenarios.

Guess you like

Origin blog.csdn.net/Z__7Gk/article/details/131916901