首页 > 编程语言 >Python——生成器、递归、内省、高阶和偏函数

Python——生成器、递归、内省、高阶和偏函数

时间:2024-08-26 19:22:08浏览次数:14  
标签:__ 函数 递归 Python 生成器 内省 print

Python的生成器(Generators)是一种特殊的迭代器,它使用类似于函数的语法定义,但是使用yield语句一次返回一个值(可以多次返回),而不是使用return语句。生成器函数允许你声明一个像迭代器那样的对象,但是你可以使用更简洁的语法来创建它们。

为什么要使用生成器?

  • 内存效率高:生成器按需产生数据,而不是在内存中创建完整的列表或数组,这对于处理大量数据尤其有用。
  • 代码简洁:生成器提供了一种简单的方式来创建迭代器。
  • 灵活性:生成器函数可以暂停执行并在后续需要时从上次停止的地方继续执行。

如何定义和使用生成器?

定义生成器

使用def语句定义一个函数,在函数中使用至少一个yield语句。每次yield调用都会暂停函数的执行,并返回紧随其后的值给调用者。下一次调用生成器的__next__()方法(或使用next()内置函数)时,函数将从上次离开的地方继续执行,直到遇到下一个yield或执行完毕。

def my_generator():  
    yield 1  
    yield 2  
    yield 3  
  
# 使用生成器  
gen = my_generator()  
print(next(gen))  # 输出 1  
print(next(gen))  # 输出 2  
print(next(gen))  # 输出 3  
# 再次调用next(gen)将引发StopIteration异常
生成器表达式

除了定义生成器函数,Python还提供了生成器表达式,这是更简洁的创建生成器的方式。生成器表达式类似于列表推导式,但是使用圆括号而不是方括号。

# 生成器表达式  
gen_exp = (x*2 for x in range(3))  
  
# 使用生成器表达式  
for value in gen_exp:  
    print(value)  # 输出 0, 2, 4

实际应用

生成器非常适合用于实现需要按需生成数据序列的场景,如文件处理、大型数据集处理、无限序列生成等。

def count(start, step=1):  
    while True:  
        yield start  
        start += step  
  
# 使用生成器生成无限序列  
counter = count(0, 2)  
for _ in range(5):  
    print(next(counter))  # 输出 0, 2, 4, 6, 8

在这个例子中,count函数创建了一个无限递增的序列,但是由于我们只在循环中请求了前五个值,所以只生成了这些值,节省了内存。

递归

Python 中的递归是一种非常强大的编程技巧,它允许函数直接或间接地调用自身。递归通常用于解决可以分解为更小、相似子问题的问题,这些问题具有相同的解决方案结构,只是规模更小。递归算法通常遵循两个基本规则:

  1. 基本情况(Base Case):一个或多个不再递归调用自己的情况,即递归的“底部”。这是算法终止的条件。
  2. 递归步骤(Recursive Step):函数体中的逻辑,该逻辑将问题分解为更小的问题,然后递归地调用自身来解决这些更小的问题。

递归示例:计算阶乘

阶乘函数 n! 是所有小于或等于 n 的正整数的乘积,其中 0! = 1。使用递归计算阶乘的 Python 代码示例如下:

def factorial(n):  
    # 基本情况  
    if n == 0:  
        return 1  
    # 递归步骤  
    else:  
        return n * factorial(n-1)  
  
# 测试递归函数  
print(factorial(5))  # 输出: 120

在这个例子中,factorial 函数首先检查基本情况(n == 0),如果为真,则返回 1(因为 0 的阶乘定义为 1)。如果基本情况不成立,函数将调用自身来计算 (n-1) 的阶乘,并将结果与 n 相乘,从而逐步解决问题。

递归的注意事项

  • 栈溢出:由于递归调用自身,如果递归没有正确终止(即缺少基本情况),或者递归深度过大,可能会导致栈溢出错误。
  • 效率问题:递归解决方案有时可能不如迭代解决方案高效,因为每次递归调用都会增加调用栈的开销。
  • 理解难度:对于复杂的递归逻辑,理解和调试可能更加困难。

递归的应用

递归在多种算法和数据结构中都有应用,包括但不限于:

  • 树的遍历(如二叉树的先序、中序、后序遍历)
  • 图的遍历(如深度优先搜索 DFS)
  • 排序算法(如归并排序)
  • 分治算法(如快速排序、汉诺塔问题)

递归是编程中一个非常强大的工具,但也需要谨慎使用,以确保其正确性和效率。

函数的参数和返回值的注释

在Python中,为函数的参数和返回值添加注释是一种很好的做法,它可以帮助其他开发者(或未来的你)更好地理解函数的功能、参数的意义以及期望的返回值。虽然Python本身并不强制要求这种注释,但是使用类型提示(Type Hints)和文档字符串(Docstrings)可以很好地达到这个目的。

类型提示(Type Hints)

从Python 3.5开始,PEP 484引入了类型提示。类型提示不是强制性的,也不会影响代码的运行,但它们可以被静态类型检查器(如mypy)使用来识别潜在的错误。

def greet(name: str, age: int) -> str:  
    """  
    向某人问好,并返回问候语。  
  
    Args:  
        name (str): 被问候者的名字。  
        age (int): 被问候者的年龄,这个参数实际上在函数体内未使用,仅作示例。  
  
    Returns:  
        str: 包含问候语的字符串。  
    """  
    return f"Hello, {name}!"

在上面的例子中,: str 和 : int 是参数nameage的类型提示,而-> str是函数返回值的类型提示。

Python的内省

Python 的内省(Introspection)是 Python 语言的一个重要特性,它允许程序在运行时检查对象的类型、属性和方法等信息。这种能力对于动态编程、调试、编写泛型代码以及构建反射式应用程序非常有用。Python 的内省功能主要依赖于其内置的几种类型和函数,比如 type()dir()getattr()hasattr()setattr(), 和 isinstance() 等。当然还有nameannotationsdoc时,它们通常与函数、类或其他可调用对象(callable objects)的元信息(metadata)相关。这些属性可以在运行时通过内省访问,以获取关于对象的有用信息。

1. __name__

__name__属性不是特定于内省的,但它是在许多Python对象上都可以找到的一个有用属性。对于函数、类、模块等,__name__给出了它们的名称(即它们在源代码中定义的名称)。

def my_function():  
    pass  
  
print(my_function.__name__)  # 输出: my_function  
  
class MyClass:  
    pass  
  
print(MyClass.__name__)  # 输出: MyClass

2. __annotations__

从Python 3.5开始,函数支持注解(Annotations),这些注解可以附加到函数参数和返回值上,以提供关于函数如何使用和期望的类型的额外信息。这些信息存储在函数的__annotations__字典中。

def my_function(a: int, b: str) -> float:  
    return float(a) + float(len(b))  
  
print(my_function.__annotations__)  
# 输出: {'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'float'>}  
# 注意:在Python 3.7之前,返回类型注解可能不会被直接存储在__annotations__中,  
# 而是通过`__return_annotation__`属性单独访问。但从Python 3.7开始,它们都统一在__annotations__中。

3. __doc__

__doc__属性包含了对象的文档字符串(docstring)。文档字符串是紧跟在函数、类、模块等定义之后的第一个字符串字面量(通常是三引号字符串),用于提供关于该对象的描述性文本。

def my_function():  
    """  
    这是一个示例函数。  
    """  
    pass  
  
print(my_function.__doc__)  
# 输出:  
#     这是一个示例函数。  
  
class MyClass:  
    """  
    这是一个示例类。  
    """  
    pass  
  
print(MyClass.__doc__)  
# 输出:  
#     这是一个示例类。

总结

  • __name__提供了对象(如函数、类、模块)的名称。
  • __annotations__包含了函数的参数和返回值的注解信息(Python 3.5+)。
  • __doc__包含了对象的文档字符串,用于提供关于对象的描述性信息。

这些属性是Python内省功能的一部分,它们允许开发者在运行时获取有关对象的有用信息。

高阶函数

Python中的高阶函数(High-Order Functions)是至少满足下列一个条件的函数:

  1. 接受一个或多个函数作为输入。
  2. 输出一个函数。

高阶函数是函数式编程中的一个核心概念,Python作为一种多范式编程语言,自然支持高阶函数。高阶函数使得代码更加模块化、可重用和灵活。下面是一些Python中常见的高阶函数示例。

reduce() 函数

reduce() 函数将一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接受两个参数,reduce()将把结果继续和序列的下一个元素做累积计算,其效果就是:reduce(f, [x1, x2, x3, ...]) = f(f(f(...f(x1, x2), x3), ...), xn)。在Python 3中,reduce()函数被移到了functools模块中。

from functools import reduce  
  
def add(x, y):  
    return x + y  
  
numbers = [1, 2, 3, 4, 5]  
sum_of_numbers = reduce(add, numbers)  
print(sum_of_numbers)  # 输出: 15

偏函数

Python的偏函数(Partial Function)是指通过固定一个或多个参数来创建一个新的函数对象。这种技术特别有用,当你需要多次调用一个函数,但每次都使用相同的某些参数值时。通过使用functools.partial,你可以很容易地创建一个这样的偏函数。

functools.partial的一般用法是:functools.partial(func, *args, **keywords),其中func是你想要部分应用的函数,*args**keywords是你想要预先填入的位置参数和关键字参数。返回的新函数会接受剩余的参数,然后将其与你之前提供的参数合并,最后调用原始函数。

下面是一个简单的例子:

from functools import partial  
  
# 定义一个简单的函数,它接受两个参数  
def add(x, y):  
    return x + y  
  
# 使用functools.partial创建一个偏函数,其中第一个参数被固定为5  
add_five = partial(add, 5)  
  
# 现在,add_five是一个新的函数,它只需要一个参数  
print(add_five(3))  # 输出: 8  
  
# 你也可以固定多个参数,或者甚至使用关键字参数  
add_five_and_ten = partial(add, 5, 10)  
print(add_five_and_ten())  # 输出: 15  
  
multiply = partial(int.__mul__)  
print(multiply(5, 3))  # 输出: 15  
  
# 使用关键字参数  
def greet(greeting, name):  
    return f"{greeting}, {name}!"  
  
greet_hello = partial(greet, greeting="Hello")  
print(greet_hello("Alice"))  # 输出: Hello, Alice!

偏函数的主要用途包括:

  1. 参数默认值:虽然Python允许在函数定义时设置参数默认值,但使用偏函数可以在不修改原始函数定义的情况下,为参数提供新的默认值。

  2. 简化函数签名:当你有一个需要多个参数的函数,但在很多情况下你都会使用相同的某些参数值时,通过创建一个偏函数,你可以减少调用时需要提供的参数数量,简化函数签名。

  3. 创建函数工厂:通过动态地生成具有特定参数集的偏函数,你可以创建一个“函数工厂”,它可以根据需要生成具有不同行为的函数。

偏函数是Python中函数式编程范式的一个例子,它允许你以更灵活和强大的方式组合和重用函数。

标签:__,函数,递归,Python,生成器,内省,print
From: https://blog.csdn.net/weixin_45720999/article/details/141568961

相关文章

  • python基础学习总结(十)
    ​文章目录面向对象一.内置内属性二.对象销毁三.类的继承四.方法重写1.基础重载方法2.运算符重载3.类的属性和方法1.类的私有属性2.类的方法3.类的私有方法五.下划线说明面向对象一.内置内属性属性|定义----|----dict|类的属性(包含一个字典,由类......
  • Python实现局部线性嵌入(LLE)降维算法
    目录Python实现局部线性嵌入(LLE)降维算法的博客引言LLE算法原理1.确定邻域2.线性重构3.降维映射Python中的LLE实现1.创建LLE类2.实现瑞士卷数据集的LLE降维3.结果分析总结Python实现局部线性嵌入(LLE)降维算法的博客引言随着数据维度的增加,高维数据的分......
  • Python实现核主成分分析(KPCA)降维算法
    目录Python实现核主成分分析(KPCA)降维算法的博客引言KPCA算法原理1.核函数与核技巧2.中心化核矩阵3.特征分解Python中的KPCA实现1.创建KPCA类2.在瑞士卷数据集上应用KPCA3.结果分析总结Python实现核主成分分析(KPCA)降维算法的博客引言在高维数据分析中,主成......
  • python学习—redis入门,新手小白轻松学
    目录一.安装redis-py库二.连接redis服务器三.基本操作(1)字符串1.一次添加一个键值对2.一次添加多个键值对3.设置存在秒数4.设置过期时间(秒)5.设置存在天数 完整代码(2)列表1.添加数据2.从右侧删除数据3.从左侧删除数据4.获取列表的长度5.根据索引查找数......
  • 基于Python语言快速批量运行DSSAT模型及交叉融合、扩展
    随着数字农业和智慧农业的发展,基于过程的作物生长模型(Process-basedCropGrowthSimulationModel)在模拟作物对气候变化的响应与适应、农田管理优化、作物品种和株型筛选、农业碳中和、农田固碳减排等领域扮演着越来越重要的作用。DecisionSupportSystemsforAgrotechnolog......
  • 【生日视频制作】广州塔表白字幕生日视频制作AE模板修改文字软件生成器教程特效素材【
    广州塔表白字幕生日视频制作教程AE模板改文字生成神器素材祝福怎么如何做的【生日视频制作】广州塔表白字幕生日视频制作AE模板修改文字软件生成器教程特效素材【AE模板】生日视频制作步骤:安装AE软件下载AE模板把AE模板导入AE软件修改图片或文字渲染出视频......
  • 【生日视频制作】一群美女挥手拉蓝横幅条幅AE模板修改文字软件生成器教程特效素材【AE
    一群美女挥手拉蓝条横幅生日视频制作教程AE模板修改文字生成器怎么如何做的【生日视频制作】一群美女挥手拉蓝横幅条幅AE模板修改文字软件生成器教程特效素材【AE模板】生日视频制作步骤:安装AE软件下载AE模板把AE模板导入AE软件修改图片或文字渲染出视频......
  • 计算机毕业设计选题-基于python的医院预约挂号系统
    精彩专栏推荐订阅:在下方专栏......
  • PyInstaller 打包 Python 程序
    使用PyInstaller打包Python程序是一个相对简单直接的过程。PyInstaller允许你将Python程序及其所有依赖项打包成一个独立的可执行文件,这样用户就可以在没有安装Python解释器的系统上运行你的程序了。以下是一个基本的步骤指南,用于使用PyInstaller打包Python程......
  • Python 多线程编程技巧举例
    Python多线程(Multithreading)是一种编程技术,允许在同一程序中同时执行多个独立的逻辑流,即线程。每个线程都有自己的程序计数器、栈空间和局部变量,它们共享同一进程的全局变量、文件描述符和其他系统资源。线程是操作系统调度的基本单位,能够在单个进程中并发运行,从而实现任务......