python中的参数传递

一、参数传递 

        在编程中,参数传递是函数或方法调用时,将值或变量从一个位置传递到另一个位置的过程。参数传递的主要方式有两种:按值传递(pass-by-value)和按引用传递(pass-by-reference)。

1.1 按值传递

  • 在这种方式中,实际参数的值被复制到函数的形式参数中。
  • 在函数内部对参数的修改不会影响原始数据。
  • 这种方式常用于基本数据类型(如整数、浮点数等)。

1.2 按引用传递

  • 这种方式传递的是参数的引用(或内存地址),因此传递的不是数据本身,而是数据的位置信息。
  • 在函数内部对参数的修改会直接影响到原始数据。
  • 这种方式常用于数组、对象等较大的数据结构,可以提高程序的效率。

二、变量和对象

        在 Python 中,变量本身不像在一些静态类型语言中那样具有固定的类型。Python中的变量是没有类型的,我们可以把它看做一个(*void)类型的指针,变量是可以指向任何对象的,而对象才是有类型的。Python 是一种动态类型语言,这意味着变量在任何时候都可以引用任何类型的对象。

2.1 变量和对象

        在 Python 中,变量可以被视为一个名字或标签,它指向计算机内存中存储的某个对象。这些对象,如整数、浮点数、字符串等,才真正拥有类型信息。当你在代码中使用变量时,实际上是在引用它指向的对象。

示例 1: 数值类型

x = 10        # x 是一个变量,指向一个整数对象 10
y = x         # y 也开始指向 x 所指向的整数对象 10

print(x)      # 输出 10
print(y)      # 输出 10

x = 20        # 现在 x 指向一个新的整数对象 20
print(x)      # 输出 20
print(y)      # 输出 10,因为 y 仍然指向原来的整数对象 10

 示例 2: 列表(可变类型)

a = [1, 2, 3]  # a 指向一个列表对象 [1, 2, 3]
b = a          # b 也指向同一个列表对象

b.append(4)    # 通过 b 修改列表
print(a)       # 输出 [1, 2, 3, 4],显示 a 和 b 指向同一个对象

a[0] = 0       # 通过 a 修改列表的第一个元素
print(b)       # 输出 [0, 2, 3, 4],再次确认 a 和 b 指向同一个对象

 示例 3: 字符串(不可变类型)

str1 = "hello"  # str1 指向一个字符串对象 "hello"
str2 = str1     # str2 也指向同一个字符串对象 "hello"

str2 = "world"  # str2 现在指向一个新的字符串对象 "world"
print(str1)     # 输出 "hello"
print(str2)     # 输出 "world"

 示例 4: 函数参数作为对象的引用

def add_item_to_list(lst, item):
    lst.append(item)  # 在列表中添加一个新项

my_list = [1, 2]
add_item_to_list(my_list, 3)
print(my_list)  # 输出 [1, 2, 3], 说明函数内部对列表的修改影响了外部的列表

 示例 5: 使用 id() 查看对象身份

c = 42
d = c
print(id(c))  # 输出 c 所指向的对象的唯一标识
print(id(d))  # 输出与 id(c) 相同的值,因为 c 和 d 指向同一个对象

c += 1        # c 现在指向一个新的对象
print(id(c))  # 输出一个不同的值,因为 c 现在指向一个新的整数对象

2.2 动态类型

        这种动态类型的特性允许变量在其生命周期内引用不同类型的对象。例如,一个变量最初可能引用一个整数,随后可以被重新赋值为引用一个字符串或其他任何类型的对象。

a = 42       # a 指向一个整数对象
print(type(a))  # 输出 <class 'int'>

a = "Hello"  # 现在 a 指向一个字符串对象
print(type(a))  # 输出 <class 'str'>

2.3 类型的检查和推断

        由于变量本身没有类型,Python 在运行时需要检查对象的类型来确定可以对对象执行哪些操作。这种类型检查是自动进行的,因此在编写代码时你无需声明变量的类型,但这也意味着可能会在运行时遇到类型错误,如果尝试对一个对象执行它不支持的操作。

2.4 指针的类比

        将变量视为 (*void) 类型的指针是一个很好的类比。在这种观点下,Python 中的变量类似于 C 语言中的通用指针,可以指向任何类型的数据。Python 的变量只是指向具体对象的引用,而所有的类型信息和数据都存储在对象本身。

2.5 内存管理

        Python 还管理着对象的生命周期,当没有任何变量引用一个对象时,该对象会被垃圾收集器回收。这种内存管理机制使得开发者可以更专注于功能开发,而不是内存管理细节。

三、python的参数传递

        Python 里所有的数据类型都是对象,所以参数传递时,只是让新变量与原变量指向相同的对象而已,并不存在值传递或是引用传递一说。在 Python 中,函数的参数传递基于“按对象的引用”(pass-by-object-reference)的策略。这种策略意味着函数接收的是对象的引用(即地址),但行为上可能看起来像是按值传递或按引用传递,这取决于对象本身是可变的还是不可变的。

  • 不可变对象(如整数、浮点数、字符串、元组等):表现类似于按值传递,因为修改不会影响原始对象。
  • 可变对象(如列表、字典、集合等):表现类似于按引用传递,因为你可以修改对象,而这些修改会反映在原始对象上。

2.1 不可变对象

        不可变对象(如整数、浮点数、字符串、元组等)的修改不会影响原始对象,因为在尝试修改这些对象时,Python 会创建一个新对象。

def modify(x):
    x = 10
    return x

a = 5
print(modify(a))  # 输出 10
print(a)          # 输出 5, 原始变量未改变

2.2 可变对象

        可变对象(如列表、字典、集合等)的修改会影响原始对象,因为这些修改操作是在原始对象上进行的。

def modify(lst):
    lst.append(3)

my_list = [1, 2]
modify(my_list)
print(my_list)  # 输出 [1, 2, 3], 原始列表被修改了

2.3 关键点

  • 参数传递方式:Python 中的参数传递既不是纯粹的按值传递,也不是纯粹的按引用传递。它是一种特殊的按对象引用传递。
  • 影响原始数据:对函数内的参数进行的修改是否影响外部的原始数据,取决于传递的数据类型(可变类型或不可变类型)。

        这种参数传递方式对于优化内存使用和提高程序效率非常重要,特别是在处理大型数据结构时。理解这一点有助于编写更有效和更安全的代码。

四、python函数参数传递的方式

        在 Python 中,函数参数可以通过多种方式传递,每种方式适用于不同的场景。这些方式包括位置传递、关键字传递、默认值传递、不定参数传递(包裹传递)和解包裹传递。

3.1 位置传递(Positional Arguments)

        位置传递是最常见的参数传递方式。函数调用时,实际参数的位置必须与函数定义中形式参数的位置一一对应。

def add(x, y):
    return x + y

result = add(5, 3)  # 5 传递给 x,3 传递给 y
print(result)  # 输出 8

3.2 关键字传递(Keyword Arguments)

        关键字传递允许函数调用者指定传递给哪一个形式参数,而不用考虑参数的位置。

def add(x, y):
    return x + y

result = add(y=3, x=5)  # 指定 y=3 和 x=5
print(result)  # 输出 8

3.3 默认值传递(Default Arguments)

        函数定义可以为一个或多个参数提供默认值。调用函数时,如果没有传递相应的参数,将使用该默认值。

def add(x, y=2):
    return x + y

print(add(5))   # 只传递 x,y 使用默认值 2,输出 7
print(add(5, 3))  # 传递 x 和 y,输出 8

3.4 不定参数传递(Arbitrary Argument Lists,也称包裹传递)

        不定参数传递允许你将不定数量的参数传递给一个函数。这通常通过在参数名前加一个星号 * 来实现。

def add(*args):
    return sum(args)

print(add(1, 2, 3))  # 可以传递任意数量的参数,输出 6

3.5  解包裹传递(Unpacking Arguments)

        如果参数已经在列表、元组或字典中,可以在函数调用时使用 *** 解包裹来传递参数。

def add(x, y, z):
    return x + y + z

values = [1, 2, 3]
print(add(*values))  # 列表解包裹,传递给 x, y, z

data = {'x': 1, 'y': 2, 'z': 3}
print(add(**data))  # 字典解包裹,传递给 x, y, z

五、总结

如果你想通过一个函数来改变某个变量的值,通常有两种方法。

  1. 第一种是直接将可变数据类型(比如列表,字典,集合)当作参数传入,直接在其上修改;
  2. 第二种则是创建一个新变量,来保存修改后的值,然后将其返回给原变量

在实际工作中,我们更倾向于使用后者,因为其表达清晰明了,不易出错。

 

  • 31
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

apple_ttt

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

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

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

打赏作者

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

抵扣说明:

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

余额充值