深入剖析 Python 函数参数传递机制及高级应用

2023-10-27

在这里插入图片描述

前言

在本篇文章中,笔者将带你深入探讨 Python 函数传参的进阶主题。
通过阅读本篇文章,你可以深入了解 Python 函数传参的进阶主题,掌握更多高级的函数技巧,提升你的 Python 编程能力。

前面分享了Python 函数传参基础篇:《提升Python函数调用灵活性:参数传递类型详解

结合食用,效果更佳。

实现⚡⚡

参数的作用域

注意事项:

  • 使用global关键字。将函数内部的 变量 声明为全局变量,使得在函数内部修改的值也能影响到函数外部。

在这个例子中,x 在函数 func 内部是一个局部变量,它的作用范围仅限于函数内部。

而在函数外部定义的 x 是一个全局变量,可以在函数内部和外部访问。

def func():
    x = 10  # 局部变量
    print("Inside func:", x)


x = 5  # 全局变量
func()
print("Outside func:", x)

输出:

Inside func: 10
Outside func: 5

如果需要改变函数外部的值,通过使用 global 关键字,将函数内部的 x 声明为全局变量,使得在函数内部修改的值也能影响到函数外部。

def func():
    global x
    x = 10  # 局部变量
    print("Inside func:", x)


x = 5  # 全局变量
func()
print("Outside func:", x)

输出:

Inside func: 10
Outside func: 10

参数的传递方式

注意事项:

  • 避免在函数内部修改可变对象:在函数内部修改可变对象这是不建议的。
  • 如果不希望函数内部的操作影响到外部变量,可以在函数内部创建一个新的可变对象,并对其进行操作,而不是直接修改传入的可变对象。
  • 需要注意函数参数传递时对象的可变性,了解不可变对象和可变对象在函数内外的表现,并根据需要采取适当的操作来避免意外修改。

理解传值传递传引用传递的区别:

  • 传值传递是将对象的副本传递给函数,函数对副本的修改不会影响到原始对象;
  • 传引用传递是将对象的引用传递给函数,函数对引用所指向的对象的修改会影响到原始对象。

这是理解参数传递方式的关键,可以帮助我们正确处理函数内外的变量关系。




在这个例子中,a 是一个不可变对象(整数),而 b 是一个可变对象(列表)。

当将它们作为参数传递给函数时,

  • 不可变对象(如整数、字符串、元组) 是通过传值传递的,所以在函数内部对 a 的修改不会影响外部变量 x

  • 可变对象(如列表、字典) 是通过传引用传递的,所以在函数内部对 b 的修改会影响外部变量 y

def modify_value(a, b):
    a = 10
    b.append(4)


x = 5
y = [1, 2, 3]
modify_value(x, y)
print(x)  # 输出: 5
print(y)  # 输出: [1, 2, 3, 4]

匿名函数和 Lambda 表达式

注意事项:

  • lambda 关键字用于定义匿名函数:lambda 关键字用于创建一个匿名函数,也称为 lambda 表达式。它可以在需要一个简单的函数定义的地方使用,并且通常用于一次性的、简单的函数需求。
  • lambda 表达式强调了函数定义的简洁性和方便性。它适用于一些简单的函数需求,可以避免编写完整的函数定义和命名的过程,使代码更加简洁和易读。
  • 匿名函数常见于函数式编程操作,如排序、过滤和映射等。它们可以作为参数传递给其他函数,使代码更加灵活和可扩展。
  • 尽管 lambda 表达式可以提供一种简洁的函数定义方式,但请注意适用场景。对于复杂的逻辑和需要复用的函数,建议使用普通函数进行定义,以提高代码的可读性和维护性。

Python lambda用法:

lambda arguments: expression

示例 1:对数字进行相加

在这个例子中,lambda 关键字用于定义一个匿名函数,它接受两个参数 xy,并返回它们的乘积。

使用 lambda 表达式可以简洁地定义简单的函数。

add_numbers = lambda x, y: x + y
result = add_numbers(5, 3)
print("Result:", result)	# 输出: 8

示例 2:对列表进行升序排序

在这个示例中,sorted() 函数使用了 key 参数,该参数接受一个函数作为排序的依据。

通过 lambda 表达式 lambda x: x,我们指定以列表中的每个元素作为排序依据。因此,列表会按照元素的大小进行升序排序。

numbers = [5, 2, 8, 1, 9]
sorted_numbers = sorted(numbers, key=lambda x: x)
print(sorted_numbers)  # 输出: [1, 2, 5, 8, 9]

示例 3:对字典列表按照字典键进行排序

在这个示例中,有一个字典列表 persons,其中每个字典包含一个名字和年龄。

使用 sorted() 函数和 key 参数,将 lambda 表达式 lambda x: x["name"] 作为排序依据。这样,字典列表将按照字典的 "name" 键进行升序排序。

persons = [
    {"name": "Alice", "age": 25},
    {"name": "Bob", "age": 30},
    {"name": "Charlie", "age": 20}
]

sorted_persons = sorted(persons, key=lambda x: x["name"])
print(sorted_persons)
# 输出: [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}, {'name': 'Charlie', 'age': 20}]

装饰器

装饰器可以实现很多有趣的功能,这里只对基础使用做一下介绍。

注意事项:

  • 确保装饰器函数的返回值是一个函数:装饰器函数必须返回一个函数对象,以便能够正确地替代原始函数。
  • 装饰器的作用是修改函数的行为:装饰器的目的是在不修改原始函数源代码的情况下,添加一些额外的功能或修改函数的行为。
  • 可以链式应用多个装饰器:Python 允许链式应用多个装饰器,即在函数定义前使用多个装饰器语句。装饰器的应用顺序与装饰器语句的顺序相反,最后应用的装饰器最先执行。
  • 装饰器的顺序是从上到下的。

示例一:将字母转换为大写装饰器

在这个例子中,uppercase_decorator 是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数。

这个装饰器函数将原始函数的返回值转换为大写形式。通过在函数定义前使用 @ 符号应用装饰器,可以直接将装饰器应用于函数。

def uppercase_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()

    return wrapper


@uppercase_decorator
def demo(name):
    return "Hello, " + name


result = demo("Frica")
print(result)  # 输出: HELLO, Frica

示例二:将字母转换为大写装饰器并添加<b>标签

在示例中,demo 函数先应用 uppercase_decorator,然后应用 bold_decorator

最终的执行顺序是先执行 bold_decorator 的包装函数,然后执行 uppercase_decorator 的包装函数。最后,调用 demo("Frica") 会返回 <b>HELLO, FRICA</b>

def uppercase_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()

    return wrapper


def bold_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return "<b>" + result + "</b>"

    return wrapper


@bold_decorator
@uppercase_decorator
def demo(name):
    return "Hello, " + name


result = demo("Frica")
print(result)  # 输出: <b>HELLO, FRICA</b>

参数的打包和解包

注意事项:

  • 打包:通过使用 *** 运算符,可以将传递给函数的参数打包成一个元组或字典;
  • 解包:通过使用 *** 运算符,可以将元组或字典中的值解构为单独的参数,并将它们传递给函数;
  • 在函数调用时,使用 * 运算符将元组中的元素分别传递给函数的位置参数;
  • 在函数调用时,使用**运算符将字典的键值对打包并传递给函数的关键字参数;
  • 通过参数解包,可以轻松地将可迭代对象的元素传递给函数,而无需一个个地指定参数的值。这种方式提供了更灵活和方便的函数调用方式,并使代码更加简洁易读。

在这个例子中,datainfo 是元组和字典,通过解构操作符 *** 将它们的值解构为单独的参数。

paramsdetails 是普通的参数值,通过打包操作符 *** 将它们的值打包成元组或字典作为参数传递给函数。

def demo(name, age):
    print(f"Name: {name},", f"Age: {age}")


# 参数解包
data = ("Frica", 25)
demo(*data)  # 输出: Name: Frica, Age: 25

# 参数解包
info = {"name": "dd", "age": 30}
demo(**info)  # 输出: Name: dd, Age: 30

参数类型注解

这个在上一篇文章中有介绍,无论何时,为你的函数和参数添加类型注解,这是很有必要的。

作用如下:

  • 提供类型提示:类型注解可以指定函数参数和返回值的预期类型,从而提供给开发者更明确的类型提示。这有助于开发者理解函数的输入和输出,并在代码编写过程中提供自动补全和错误检查的功能。
  • 增加代码可读性:类型注解可以提高代码的可读性,使代码更加清晰易懂。通过类型注解,开发者可以清楚地了解函数参数的期望类型,从而更好地理解函数的作用和用法。
  • 增强代码健壮性:类型注解可以在编译时或运行时进行类型检查,从而捕获潜在的类型错误。通过类型检查,可以避免在函数调用时传递错误类型的参数,提前发现并修复类型相关的问题,提高代码的健壮性和可靠性。
  • 提升代码维护性:类型注解可以帮助开发团队更好地理解代码,并减少对代码的误解。在代码维护和重构过程中,类型注解可以作为重要的参考信息,帮助开发者正确修改和调整函数的使用方式。
  • 支持静态类型检查工具:添加类型注解可以支持使用静态类型检查工具,例如 MyPy、Pyright 等。这些工具可以对代码进行静态分析,发现类型相关的问题,并提供进一步的建议和修复方案。

需要注意的是,类型注解并不会影响代码的实际执行,它们只是提供给开发者和工具使用的信息。

在 Python 中,类型注解是可选的,并且不会导致运行时错误。但是,类型注解可以在代码开发和维护过程中提供很多有益的帮助,

def demo(name: str, age: int) -> str:
    return "Hello, " + name + "! You are " + str(age) + " years old."


print(demo("Frica", 25))	# 输出: Hello, Frica! You are 25 years old.

总结✨✨

本篇文章深入介绍了Python中函数传参机制的高级应用。

  • 参数的作用域:介绍了局部作用域、全局作用域和嵌套作用域的概念及其关系。这有助于理解在不同作用域中如何访问和操作变量。

  • 参数的传递方式:探讨了传值调用和传引用调用的区别,以及可变对象和不可变对象的概念。这对于理解函数参数的传递机制非常重要。

  • 匿名函数和 Lambda 表达式:介绍了匿名函数的定义和使用,以及 Lambda 表达式的语法和应用场景。这些技巧可以简化代码并提高可读性。

  • 装饰器:解释了装饰器的作用和用法,包括如何定义和应用装饰器来增强函数的功能。装饰器是 Python 中强大的函数修饰工具。

  • 参数的解构和打包:讨论了参数解构和打包的操作符 *** 的使用方法,以及如何处理多个参数的情况。这些技巧可以增加代码的灵活性。

  • 参数类型注解:介绍了参数类型注解的概念和用法,以及如何在函数定义时指定参数的类型。这有助于提高代码的可读性和可维护性。

总体上,这些主题涵盖了函数传参的关键概念和技巧,适合进阶的 Python 程序员学习和掌握。

后话

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入剖析 Python 函数参数传递机制及高级应用 的相关文章

  • 同一台机器上有多个Python版本?

    Python 网站上是否有关于如何在 Linux 上的同一台计算机上安装和运行多个版本的 Python 的官方文档 我可以找到无数的博客文章和答案 但我想知道是否有 标准 官方方法可以做到这一点 或者这一切都取决于操作系统 我认为它是完全独
  • Django 1.7 应用程序配置导入错误:没有名为 appname.apps 的模块

    我正在尝试按照以下文档为我的一个名为 文章 的 Django 应用程序设置自定义应用程序配置https docs djangoproject com en dev ref applications https docs djangoproj
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • 导入目录下的所有模块

    有没有办法导入当前目录中的所有模块 并返回它们的列表 例如 对于包含以下内容的目录 mod py mod2 py mod3 py 它会给你
  • Android - 存储对ApplicationContext的引用

    我有一个静态 Preferences 类 其中包含一些应用程序首选项和类似的内容 可以在那里存储对 ApplicationContext 的引用吗 我需要该引用 以便我可以在不继承 Activity 的类中获取缓存文件夹和类似内容 你使用的
  • 从三点求圆心的算法是什么?

    我在圆的圆周上有三个点 pt A A x A y pt B B x B y pt C C x C y 如何计算圆心 在Processing Java 中实现它 我找到了答案并实施了一个可行的解决方案 pt circleCenter pt A
  • 如何全局安装 Python(开发)依赖项,以便我不必在每个 venv 中重新安装它们?

    我希望在为每个项目创建的每个 venv 虚拟环境 中都可以使用一些 Python 依赖项 例如 black flake8 和 pytest 这可能吗 如果可以 如何实现 我想安装这三个once在我的主要 Python 安装下 我必须在启动新
  • 如何使用 Jersey 将嵌套列表封送为 JSON?我得到一个空数组或一个包含数组的单元素字典数组

    我正在开发一个使用 Jersey 将对象转换为 JSON 的项目 我希望能够写出嵌套列表 如下所示 data one two three a b c 我想要转换的对象首先将数据表示为 gt gt 我认为 Jersey 会做正确的事情 以上输
  • Python 或 C 语言中的 Matlab / Octave bwdist()

    有谁知道 Matlab Octave bwdist 函数的 Python 替代品 此函数返回给定矩阵的每个单元格到最近的非零单元格的欧几里得距离 我看到了一个 Octave C 实现 一个纯 Matlab 实现 我想知道是否有人必须用 AN
  • 如何在 Python 中跟踪日志文件?

    我想在 Python 中提供 tail F 或类似内容的输出 而无需阻塞或锁定 我找到了一些非常旧的代码来做到这一点here http code activestate com recipes 436477 filetailpy 但我认为现
  • 无法将matplotlib安装到pycharm

    我最近开始使用Python速成课程学习Python编程 我陷入困境 因为我无法让 matplotlib 在 pycharm 中工作 我已经安装了pip 我已经通过命令提示符使用 pip 安装了 matplotlib 现在 当我打开 pych
  • Android计算两个日期之间的天数

    我编写了以下代码来查找两个日期之间的天数 startDateValue new Date startDate endDateValue new Date endDate long diff endDateValue getTime star
  • 用于请求带有临时缓存的远程 Observable 的 RxJava 模式

    用例是这样的 我想暂时缓存最新发出的昂贵的Observable响应 但在它过期后 返回到昂贵的源Observable并再次缓存它 等等 一个非常基本的网络缓存场景 但我真的很难让它工作 private Observable
  • Python matplotlib:将轴标签/图例从粗体更改为常规粗细

    我正在尝试制作一些出版质量的图 但遇到了一个小问题 默认情况下 matplotlib 轴标签和图例条目的权重似乎比轴刻度线重 是否有办法强制轴标签 图例条目与刻度线的重量相同 import matplotlib pyplot as plt
  • Android ScrollView,检查当前是否滚动

    有没有办法检查标准 ScrollView 当前是否正在滚动 方向是向上还是向下并不重要 我只需要检查它当前是否正在滚动 ScrollView当前形式不提供用于检测滚动事件的回调 有两种解决方法可用 1 Use a ListView并实施On
  • 在 anaconda 环境下运行 qsub

    我有一个程序 通常在 Linux 的 conda 环境中运行 因为我用它来管理我的库 指令如下 source activate my environment python hello world py 我怎样才能跑你好世界 py在与 PBS
  • OSError: [WinError 193] %1 不是有效的 Win32 应用程序,同时使用 CTypes 在 python 中读取自定义 DLL

    我正在尝试编写用 python 封装 C 库的代码 我计划使用 CTypes 来完成此操作 并使用 Visual Studio 来编译我的 DLL 我从一个简单的函数开始 在 Visual Studio 内的标头中添加了以下内容 然后将其构
  • 设置 TreeSet 的大小

    有没有办法像数组一样对 Java 集合中的 TreeSet 进行大小限制 例如我们在数组中 anArray new int 10 数组具有固定长度 在创建数组时必须指定该长度 A TreeSet当您向其中添加元素时会自动增长 您无法设置其大
  • 正则表达式 - 匹配不包含字符串的模式

    我对正则表达式很陌生 并且一直在寻找方法来做到这一点 但没有成功 给定一个字符串 我想删除以 abc 开头 以 abc 结尾且中间不包含 abc 的任何模式 如果我做 abc abc abc 它将匹配以 b 开头 以 abc 结尾并且中间包
  • 关闭扫描仪是否会影响性能

    我正在解决一个竞争问题 在问题中 我正在使用扫描仪获取用户输入 这是 2 个代码段 一个关闭扫描器 一个不关闭扫描器 关闭扫描仪 import java util Scanner public class JImSelection publ

随机推荐

  • 定时器每隔n秒请求n条数据,setInterval分批请求数据

  • 前端测试——端对端测试框架 Playwright 总结

    在进行前端测试前 我们需要明确我们需要怎样的前端测试 前端测试类型总结 前端应用测试分为几种常见类型 端到端 e2e 一个辅助机器人 表现得像一个用户 在应用程序周围点击 并验证其功能是否正确 常见的测试框架是 Playwright 单元
  • 引导过程以及服务控制

    目录 服务器开机过程 开机自检 BIOS MBR主引导程序 grub菜单 加载内核 init初始化 步骤说明 初步检测 mbr引导 加载linux内核 驱动系统 系统初始化 命令 控制类型 运行级别相关命令 运行级命令 服务器开机过程 开机
  • 管理科学与工程 国内核心期刊 国外a刊及SCI

    国内 管理科学与工程 管理科学学报 A 匿名审稿 绝对牛刊 不比一般的SCi期刊的质量差 系统工程理论与实践 A 实名审稿 关系稿很多 尤其是挂编委的文章很多 但质量尚可 系统工程学报 A 匿名审稿 侧重方法论多写 编辑部的老师特好 中国管
  • unity 判断是否点击在某个面板身上

    using System Collections using System Collections Generic using UnityEngine public class TestImage MonoBehaviour Use thi
  • 随机变量序列的收敛性质分类

    分类 X n 趋向某个固定的数 X n 趋向某个确定函数的输出值 X n 的概率分布越来越接近某个特定的随机变量的概率分布 X n 和某个特定随机变量的差别的平均值 数学期望值 趋向于0 X n 和某个特定随机变量的差别的方差趋向于0 约束
  • 面试题:String 和 StringBuilder、StringBuffer 的区别?

    Java 平台提供两种类型的字符串 String 和 StringBuffer StringBuilder 它们可以存储和操作字符串 其中String是只读字符串 也就意味着String 引用的字符串内容是不能被改变的 而StringBuf
  • 多益网络校招笔试题

    马上要参加多益的笔试了 所以在网上找了一下多益的笔试题 原文 我感觉我想出了一个更简单的方法 时间复杂度O 1 如果有问题希望大家及时指正 题目如下 给定一个数x x gt 5 找到该数与3 4之间的关系 关系如下 x 3 n 4 m 然后
  • 最近我在忙什么之【毕业设计大纲】

    毕业设计工作日志 误差校正仿真 理论部分 Stewart平台位姿误差分析与标定研究 仿真部分 基于Matlab的全局搜索 单通道控制算法设计 滑模论文 根据论文仿真 填入参数 获取具体的传递函数 改进滑模的论文 扰动及对照实验设计 稳定平台
  • Ubuntu下使用MySQL(C++,Cmake)

    安装需要使用的库 sudo apt get install libmysqlclient dev 头文件 usr include mysql mysql的头文件在这里 引入头文件 include mysql h 如果找不到就 include
  • python web.py+requests 视频接收与发送

    web py是python中一个相对容易上手的web服务器搭建工具 1 安装方式 web py可以直接通过pip install 的方式安装即可 即 pip install web py 2 服务器 2 1 完整程序 import web
  • 迷宫问题—回溯法

    文章目录 一 项目分析的一般步骤 二 迷宫问题的具体解决 1 需求分析 2 问题分析 2 1 问题分析 2 2 数据结构设计的分析 3 设计 流程图设计 代码设计 3 1流程图设计 3 2代码设计 4 代码测试 5 完成交付 一 项目分析的
  • Springboot+Mybatis,dao加上@Repository注解无法注入

    在springboot 中 给mapper的接口上加上 Repository 无法生成相应的bean 从而无法 Autowired 这是因为spring扫描注解时 自动过滤掉了接口和抽象类 这种情况下可以在启动的类前加 上 MapperSc
  • 如何在 Python 中创建元组字典

    本演练是关于在 Python 中创建元组字典的全部内容 此数据结构存储键值对 通过组合字典和元组 可以创建元组字典 好处是以结构化格式组织且可访问的数据 可以轻松表示每个键的多个值 例如学生成绩或联系信息 让我们看看它如何有效地存储和检索复
  • 抖音生活小妙招类短视频创作技巧分享,几个方面带你了解整个流程

    想做抖音 又不想真人出镜 该选择什么项目做呢 更多精彩干货请关注共众号 萤火宠 免费领取108个抖音小项目 我们的学员中有宝妈 有大学生 也有不少职场人员 他们大多数都非常普通 没有什么很强的职业技能 也没有什么丰富的专业知识 但是他们有人
  • 找实习、工作的一点浅见

    一 实习的必要性 为什么需要去实习 1 实习能帮助自己增进对于具体职场的认识 包括具体工作的职责 内容 工作氛围 是否有较大压力等等 2 通过一段时间的实习经历 能帮助自己作出未来是否能胜任类似的工作的判断 如果有留用 是否考虑留下 如果没
  • 阿里的iOS协程库 coobjc 源码解析(一)——元组和协程

    Coobjc中的元组 底层主要依赖NSPointerArray进行实现 因为NSPointerArray支持插入nil指针 能配合元组中有对象为nil的特性 比较引人入胜的设计 主要是co tuple 这个宏定义 co tuple COTu
  • 学习笔记:SpringCloud 微服务技术栈_实用篇②_黑马旅游案例

    若文章内容或图片失效 请留言反馈 部分素材来自网络 若不小心影响到您的利益 请联系博主删除 前言 学习视频链接 SpringCloud RabbitMQ Docker Redis 搜索 分布式 史上最全面的 SpringCloud 微服务技
  • CSS水平垂直居中

    1 利用定位 margin auto 2 flex布局 3 grid布局 一 利用position margin auto
  • 深入剖析 Python 函数参数传递机制及高级应用

    前言 在本篇文章中 笔者将带你深入探讨 Python 函数传参的进阶主题 通过阅读本篇文章 你可以深入了解 Python 函数传参的进阶主题 掌握更多高级的函数技巧 提升你的 Python 编程能力 前面分享了Python 函数传参基础篇