Python 函数的一些用法

高阶函数

将函数 a 作为变量传给另一个函数 b,函数 b 就是一个高阶函数。

def b(a):
    num = 2 - 5
    return a(num)
a = abs
result = b(a)
print(result) # 3

Python 内置的高阶函数中,有几个很常用。

map() 函数。

如果想要将一个可迭代对象中的元素全部按照某种规则修改,就可以用 map()
map() 的用法为:map(func, iter)

  • func:是一个函数,表示规则
  • iter:是可迭代对象

比如想要把列表 [1, 2, 3] 的元素全部乘 2,可以这样写:

demo_list = [1, 2, 3]
result = map(lambda x: x * 2, demo_list)
print(list(result)) # [2, 4, 6]

map() 返回迭代器,常与 lambda 配合使用。

reduce() 函数

reduce() 描述起来不太直观,直接看示例。
reduce() 的用法为:reduce()

  • func:是一个接收两个参数的函数,表示规则
  • iter:是可迭代对象

比如给出一个列表,想要求和:[1, 2, 3, 4]

from functools import reduce

demo_list = [1, 2, 3, 4]
result = reduce(lambda x, y: x + y, demo_list)
print(result) # 10

在这个例子中,先把 12 分别作为 xy,其返回值和后一个元素 3 分别作为下一个 xy,按照这样递归的模式一直执行,直到迭代完成,返回结果。
reduce 也可配合 lambda 使用。

reduce() 结合 map() 可以写一个将字符串转为整型的算法。

from functools import reduce
STR_2_INT_MAP = {
    "0" : 0,
    "1" : 1,
    "2" : 2,
    "3" : 3,
    "4" : 4,
    "5" : 5,
    "6" : 6,
    "7" : 7,
    "8" : 8,
    "9" : 9,
}
demo_str = "12345"
result = reduce(
    lambda a, b : a * 10 + b,
    map(
        lambda x : STR_2_INT_MAP[x],
        demo_str
    )
)
print(result) # 12345

filter() 函数

filter() 可以从可迭代对象中筛选出符合给定的规则的元素,返回生成器。
写法:filter(func, iter)

  • func:是一个函数,表示规则
  • iter:可迭代对象

比如筛选出 [1, 2, 3, 4, 5, 6, 7] 中的偶数:

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

sorted() 函数

写法:sorted(iter, key, reverse)

  • iter:可迭代对象
  • key:是一个函数,排序的规则,这个参数是内置的
  • reverse:是否反转,这个参数是内置的

比如要得到 [3, 6, 3, 8, 9, 6, 7, 1] 排序后的结果:

demo_list = [3, 6, 3, 8, 9, 6, 7, 1]
result = sorted(demo_list)
print(result) # [1, 3, 3, 6, 6, 7, 8, 9]

sorted()sort() 不同,
sorted(demo_list) 返回一个新列表,内容是排序的结果,
demo_list.sort() 是直接改变了 demo_list,且没有返回值。

闭包

闭包实质上就是函数里面再写个函数,然后把子函数作为返回值,子函数的数量无限制。

一个常规的求和函数可以是这样:

def get_sum(nums):
    result = 0
    for num in nums:
        result += num
    return result
nums = [1, 2, 3, 4, 5]
result = get_sum(nums)
print(result) # 15

将这个求和函数改成懒加载的形式:

def get_sum(nums):
    def inner_sum():
        result = 0
        for num in nums:
            result += num
        return result
    return inner_sum
nums = [1, 2, 3, 4, 5]
func_result = get_sum(nums)
print(func_result) # <function get_sum.<locals>.inner_sum at 0x7fc11311e940>
print(func_result()) # 15

闭包中的子函数引用的是变量,而不是变量的值。比如下面这个闭包:

def square():
    result = []
    for num in [1, 2, 3]:
        def sq():
            return num * num
        result.append(sq)
    return result
re1, re2, re3 = square()
print(re1) # <function square.<locals>.sq at 0x7fc11272a700>
print(re2) # <function square.<locals>.sq at 0x7fc11272aca0>
print(re3) # <function square.<locals>.sq at 0x7fc11272a940>

"""
这三个函数引用中,引用的是 num * num 这个变量,不是值
当循环结束后,num 已经都变成了 3,所以全部返回 9。
"""
print(re1()) # 9
print(re2()) # 9
print(re3()) # 9

如果一定要引用值,就要再加一层子函数:

def square():
    def sq(num):
        def sq_value():
            return num * num 
        return sq_value
    result = []
    for num in [1, 2, 3]:
        result.append(
            sq(num)
        )
    return result

re1, re2, re3 = square()
print(re1) # <function square.<locals>.sq.<locals>.sq_value at 0x7fc1127d5ca0>
print(re2) # <function square.<locals>.sq.<locals>.sq_value at 0x7fc1127d5940>
print(re3) # <function square.<locals>.sq.<locals>.sq_value at 0x7fc1127d5430>

print(re1()) # 1
print(re2()) # 4
print(re3()) # 9

装饰器

装饰器可以在不改变函数逻辑的情况下,增加一些功能。比如给出一个求和函数:

def get_sum():
    nums = [1, 2, 3, 4, 5]
    result = 0
    for num in nums:
        result += num
    return result
result = get_sum()
print(result) # 15

现在如果要在运行这个函数的开始打印日志,就可以另写一个函数 dec_get_sum(),然后在 get_sum() 头上加 @dec_get_sum 实现装饰器的效果。

def dec_get_sum(func):
    def wrapper(*args, **kwargs): # 形参写作 *args, **kwargs,表示接受任何参数
        print(
            f"开始求和...函数名称为:{func.__name__}" # func.__name__ 可以拿到函数的名称
        )
        return func(*args, **kwargs)
    return wrapper

@dec_get_sum
def get_sum():
    nums = [1, 2, 3, 4, 5]
    result = 0
    for num in nums:
        result += num
    return result
result = get_sum()
print(result)
"""
开始求和...函数名称为:get_sum
15
"""

给函数加装饰器 @dec_get_sum 等效于执行:get_sum = dec_get_sum(get_sum)
如果要自定义日志的内容,装饰器函数就需要在外面再套一层:

import functools
def print_log(text):
    def dec_get_sum(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs): # 形参写作 *args, **kwargs,表示接受任何参数
            print(
                f"开始求和...当前时间为:{text},函数名称为:{func.__name__}" # func.__name__ 可以拿到函数的名称
            )
            return func(*args, **kwargs)
        return wrapper
    return dec_get_sum

import time
@print_log(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
def get_sum():
    nums = [1, 2, 3, 4, 5]
    result = 0
    for num in nums:
        result += num
    return result
result = get_sum()
print(result)
"""
开始求和...当前时间为:2021-09-07 11:44:21,函数名称为:get_sum
15
"""

print(get_sum.__name__) # 'wrapper'

@print_log("text") 的实质是:get_sum = print_log("text")(get_sum)

这时如果打印一下 get_sum__name__,发现函数名称已经被改变了,需要用一个内置的方法修正:functools.wraps(func)。修改后的代码如下:

import functools
def print_log(text):
    def dec_get_sum(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs): # 形参写作 *args, **kwargs,表示接受任何参数
            print(
                f"开始求和...当前时间为:{text},函数名称为:{func.__name__}" # func.__name__ 可以拿到函数的名称
            )
            return func(*args, **kwargs)
        return wrapper
    return dec_get_sum

import time
@print_log(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
def get_sum():
    nums = [1, 2, 3, 4, 5]
    result = 0
    for num in nums:
        result += num
    return result
result = get_sum()
print(result)
"""
开始求和...当前时间为:2021-09-07 11:50:59,函数名称为:get_sum
15
"""

print(get_sum.__name__) # get_sum

偏函数

想要改变函数的某个参数的默认值,作为一个新函数,这时就可以用偏函数。

比如对于内置的 int() 函数:
int() 函数实质为:指定参数的进制,返回其 10 进制,可以用 base 指定当前参数的进制。

print(int("123")) # 123,base 默认为10,0 也是十进制
print(int("123", base=2)) # 报错,因为123不是二进制数
print(int("010101", base=2)) # 21

定义一个二进制转十进制的函数

import functools
bin_2_dec = functools.partial(int, base=2)
print(bin_2_dec("010101")) # 21

(本文完)

原文地址:https://www.cnblogs.com/junsircoding/p/15664976.html