讲讲Python中的普通函数和高阶函数

本文详细讲解了Python函数的基础概念,包括函数定义、嵌套调用,以及高阶函数的使用。通过实例演示如何利用高阶函数简化计算,如面积计算的通用化方法。还介绍了lambda函数的应用和一个实际场景中的代码示例。

正式的Python专栏第25篇,同学站住,别错过这个从0开始的文章!

今天学委都在写代码,写了很多篇,这次再讲讲python中的函数

什么是函数

每个语言都有函数,甚至大家用的Excel里面也有函数,我们以前学习的数学也很多各种各样的函数。

Python中的函数也是一样的。

def f(x):
    print("参数为:",x)
    return x

这里的函数 y = f(x), 在数学中表示为一条斜率为1的直线。

函数的嵌套调用

def z(x):
    pass

def f(x):
    print("参数为:",x)
    return z(x)

像这样,我们在f(x)中调用了z(x)函数(这里使用了pass关键字,实现先不写,仅作展示目的)

我们能不能不定义z(x)就定义一个函数调用别的函数呢?

就像实现一个数的平方,函数的‘平方’,大概这个意思。

高阶函数

def f(z):
    return z()

这就是高阶函数,f函数需要外界提供一个参数,这个参数必须是一个函数。

在使用f(z)的时候,我们不能给一个f(2), f(3)这样的值。或者有个函数如d(x)返回非函数值结果,我们不能这样调用:f(d(1))。

学委准备了下面的代码,从简单函数逐步演化为高阶函数:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/10/24 11:39 下午
# @Author : LeiXueWei
# @优快云/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : func_demo2.py
# @Project : hello

def f1(x):
    return x


def f2(x, z=100):
    return x + z / 10


def f3(x, z=100, *dynamic_args):
    sum = 0
    for arg in dynamic_args:
        sum += arg
    return x + z / 10 + sum / 10000.0


def dummy_sum(*args):
    return 0


def f4(x, z=100, sum_func=dummy_sum):
    return x + z / 10 + sum_func() / 10000.0


print(f1(100))
print(f2(100, z=50))
print(f3(100, 50, 4, 5, 6))


def sum_g(*dynamic_args):
    def sum_func():
        sum = 0
        for arg in dynamic_args:
            sum += arg
        return sum
    return sum_func



print(f4(100, 50, sum_g(4, 5, 6)))

这里我们看到函数f1, f2, f3, f4。

补充一个知识点: *dynamic_args 是一个动态参数,不定长度的参数。
也就是f3明明声明了3个参数,最后我们给了5个参数。
这里f3认为x=100, z=50, dynamic_args = [4, 5, 6]

我们先看看输出结果:

屏幕快照 2021-10-31 下午9.19.28.png

f3 和f4 看起来结果一样。

但是性质完整不一样,读者可以思考十秒。

f4弹性非常大,因为第三个参数为函数。

高阶函数可以帮助我们把计算‘降维’(三维变成二维,二维变一维)。

我们思考一下计算圆形和方形的面积

相信大家闭着眼都能写出下面两个函数:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/10/24 11:39 下午
# @Author : LeiXueWei
# @优快云/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : func_demo2.py
# @Project : hello
import math


def circle_area(r):
    return math.pi * r * r


def rectangle_area(a, b):
    return a * b

这是圆形面积的数学公式:
f ( r ) = π ∗ r 2 f(r) = \pi * r^2 f(r)=πr2
这是矩形面积的数学公式:
f ( a , b ) = a ∗ b f(a, b) = a * b f(a,b)=ab

我们看到这里有的有1个参数的,有的有两个的怎么变成高阶函数?

读者可以思考一会。

下面是代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/10/24 11:39 下午
# @Author : LeiXueWei
# @优快云/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : func_demo2.py
# @Project : hello
import math


def circle_area(r):
    return math.pi * r * r


def rectangle_area(a, b):
    return a * b


def area(x, linear, factor):
    return x * linear(x, factor)


def relation(x, factor):
    return x * factor


a = 10
b = 20

print("长方形面积:", rectangle_area(a, b))
print("圆形面积:", circle_area(a))
print("长方形面积:", area(a, relation, factor=b / a))
print("圆形面积:", area(a, relation, factor=math.pi))

结果如下图:

屏幕快照 2021-10-31 下午9.41.56.png

这只是一种解法。

从代码可以看到,我们把圆形和矩形都看作某一个参照物(半径/一条边)的平方,再成乘以一个系数。

下面,我们把正方形面积计算加上:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/10/24 11:39 下午
# @Author : LeiXueWei
# @优快云/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : func_demo2.py
# @Project : hello
import math


def circle_area(r):
    return math.pi * r * r


def square_area(a):
    return a * a


def rectangle_area(a, b):
    return a * b


def area(x, linear, factor):
    return x * linear(x, factor)


def relation(x, factor):
    return x * factor


a = 10
b = 20

print("长方形面积:", rectangle_area(a, b))
print("正方形面积:", square_area(a))
print("圆形面积:", circle_area(a))
print("长方形面积:", area(a, relation, factor=b / a))
print("正方形面积:", area(a, relation, factor=1))
print("圆形面积:", area(a, relation, factor=math.pi))

上面的代码执行结果如下:

屏幕快照 2021-10-31 下午9.45.26.png

这就是高阶函数的神奇之处,我们从正方形的角度思考。

只用一个area函数和relation函数,这两个函数都不必修改,只需要给一个factor(经验因子),就能快速计算它的面积。

为何高阶函数能够降低维度

从上面距离的计算面积的函数,我们可以看到计算圆形和长方形,都能看成一个一维函数。

然后以正方形面积为参照物,快速估算出圆形和方形的面积。

当然上面的计算圆形面积采用了半径,还不够直观,读者可以自行改为直径,这样factor = math.pi / 4。

这样在感受上会更贴切。

总结

除了上面介绍的函数,参数,高阶函数。我们还可以使用lambda函数:

lambda  参数1, 参数2,。。。,第n个参数 : 计算表达式

上面的函数relation函数可以省略不写,最后调用改为:

print("长方形面积:", area(a, lambda x, f: x * f, factor=b / a))
print("正方形面积:", area(a, lambda x, f: x * f, factor=1))
print("圆形面积:", area(a, lambda x, f: x * f, factor=math.pi))

对了,喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏

持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!

<think>嗯,用户想了解隐匿函数(即匿名函数普通函数的区别。这个问题在编程基础中很常见,但用户可能刚接触函数式编程概念,需要清晰直观的对比。 从引用材料看,用户提供的参考资料已经点出关键:匿名函数的核心优势是简洁性即用性(引用[1]),而普通函数更适合复杂逻辑(引用[2]提到clean code原则)。不过用户混淆了“隐匿”“匿名”的术语,需要先确认是lambda函数。 用户可能正在学习Python,因为所有引用示例都是Python代码。ta的困惑点或许在于:为什么有时候用lambda更方便,有时候又必须用def?这涉及到函数式编程范式(引用[3])代码可维护性的平衡(引用[4]强调基础扎实的重要性)。 需要重点区分的维度包括:语法结构、作用域、调试难度。比如lambda不能写return语句这种隐性规则,对新手容易造成坑。还要注意用户可能延伸思考装饰器(引用[3]示例),可以留作问题拓展。 最后组织对比表格时,要把“适用场景”放在突出位置——毕竟用户真正需要的是决策依据(什么时候用哪种)。性能差异虽然存在,但现代解释器优化后差距很小,不必过度强调。</think>好的,我们来详细探讨一下匿名函数(通常称为Lambda函数)与普通函数(通常使用`def`关键字定义)在编程中的主要区别。 **核心区别:** 匿名函数普通函数的核心区别在于**定义方式、命名、作用域复杂度**。 1. **定义方式与命名:** * **普通函数 (`def`):** * 使用 `def` 关键字显式定义。 * **必须有一个名称**。这个名称是函数对象的标识符,用于后续调用引用。 * 示例: ```python def add(x, y): return x + y ``` * **匿名函数 (`lambda`):** * 使用 `lambda` 关键字隐式定义。 * **没有显式的名称**。`lambda` 本身不是函数名,它只是一个创建匿名函数的工具。函数体本身没有绑定到一个标识符上。 * 示例: ```python lambda x, y: x + y # 这是一个匿名函数表达式 ``` 2. **作用域与可访问性:** * **普通函数 (`def`):** * 在定义它的作用域(模块、类、函数)内创建一个具有指定名称的函数对象。 * 该名称在该作用域内是持久的,可以被多次调用,甚至可以在其他作用域通过导入或传递来访问。 * **匿名函数 (`lambda`):** * 本身没有绑定名称,**通常作为表达式的一部分立即使用**。 * 为了能重复使用,**必须将其赋值给一个变量**(这时变量名指向该函数对象,但函数本身仍然是匿名的)或**作为参数传递给另一个函数**(如 `map`, `filter`, `sorted` 的 `key` 参数等)。 * 示例(赋值给变量): ```python add_lambda = lambda x, y: x + y # 变量 add_lambda 指向匿名函数 result = add_lambda(5, 3) # 通过变量名调用 ``` 3. **函数体复杂度:** * **普通函数 (`def`):** * 函数体可以包含**任意数量**的语句(赋值、条件判断、循环、其他函数调用等)。 * 可以包含**文档字符串 (`docstring`)** 用于说明函数用途。 * 使用 `return` 语句显式返回结果。 * **匿名函数 (`lambda`):** * 函数体**只能是单个表达式**。 * **不能包含语句**(如赋值 `=`, `if-elif-else` 块, `for/while` 循环等)。只能使用条件表达式 (`x if condition else y`) 实现简单逻辑。 * **隐式返回**该表达式的结果,不需要(也不能)写 `return` 关键字。 * **不能包含文档字符串 (`docstring`)**。 * 示例(合法): ```python # 使用条件表达式 is_even = lambda x: True if x % 2 == 0 else False # 作为参数传递 sorted_list = sorted(my_list, key=lambda item: item['age']) ``` * 示例(非法,因为包含语句): ```python # 错误!lambda 体不能包含赋值语句 lambda x: y = x * 2; return y ``` 4. **设计目的与适用场景:** * **普通函数 (`def`):** * 用于定义**可重用、逻辑复杂**的功能块。 * 当函数需要被**多次调用**或在**不同上下文中使用**时。 * 当需要清晰的**函数名****文档说明**以增强代码可读性可维护性时。 * 是构建程序**模块化结构**的基础。 * **匿名函数 (`lambda`):** * 主要用于**需要小型函数作为参数**传递的场合,即作为**高阶函数**(接受函数作为参数的函数)的参数。这是其最典型最有价值的应用场景[^1]。 * 适用于**逻辑非常简单**,**只需一行表达式**就能完成的操作。 * 强调**简洁性****即时性**,避免为了一个微小的、一次性使用的操作而专门去定义一个命名函数[^1][^2]。 * 在函数式编程范式中更常见[^2][^3]。 **总结对比表:** | 特性 | 普通函数 (`def`) | 匿名函数 (`lambda`) | | :----------------- | :---------------------------------------- | :------------------------------------------ | | **定义关键字** | `def` | `lambda` | | **名称** | 必须有显式名称 | 无显式名称(本身匿名) | | **函数体** | 可包含多个语句,复杂逻辑 | **只能是单个表达式** | | **返回** | 使用 `return` 语句显式返回 | **隐式返回**表达式结果 | | **文档字符串** | 可包含 (`"""docstring"""`) | **不可包含** | | **赋值/循环/条件块**| 支持 (`=`, `if/elif/else`, `for`, `while`) | **不支持** (仅能用条件表达式 `x if c else y`) | | **主要用途** | 定义可重用、复杂功能的模块 | **作为参数传递给高阶函数**,定义简单一次性操作 | | **适用场景** | 通用、复杂逻辑、需要多次调用、需文档说明 | 简单逻辑、一次性使用、函数式编程参数传递 | | **代码风格** | 过程式编程、面向对象编程基础 | 函数式编程风格体现[^2][^3] | | **可读性 (复杂时)**| 通常更好(有名称文档) | 过度使用或复杂逻辑会降低可读性 | **简单来说:** * 当你需要一个**有名字的、逻辑可能比较复杂、需要多次调用或需要文档说明**的函数时,用 **`def`**。 * 当你需要一个**非常简单的、一次性使用的、尤其是需要作为参数传递给另一个函数(如 `map`, `filter`, `sorted(key=)`)** 的小函数时,考虑用 **`lambda`** 来写会更简洁[^1][^2]。 **引用说明:** * [^1]: 引用[1]强调了匿名函数的简洁性作为参数传递的适用性。 * [^2]: 引用[2]提到了匿名函数(lambda)与普通函数(`def`)在编程范式上的差异(过程式 vs 函数式)。 * [^3]: 引用[3]虽然主要讲装饰器,但装饰器常作用于函数,且函数作为一等公民(可被传递、修饰)的概念是理解高阶函数匿名函数应用的基础。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雷学委

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值