Python中级之可变数据类型和不可变数据类型
【一】可变数据类型
- 对于可变类型(如字典、列表、集合),在函数中修改参数会影响原始对象。
- 当你对于可变类型进行修改操作,并不会返回内容,而是将原本的内容进行了更新
# 字典(dict)
dict1 = {'a': 1, 'b': 2}
dict1.update({'c': 2})
print(dict1) # {'a': 1, 'b': 2, 'c': 2}
# 列表(list)
list1 = ['a', 'b', 'c']
list1.append('d')
print(list1) # ['a', 'b', 'c', 'd']
# 集合(set)
set1 = {1, 2, 3, 4}
set1.add(5)
print(set1) # {1, 2, 3, 4, 5}
【二】不可变数据类型
- 对于不可变类型(如数值、字符串、布尔),在函数中修改参数不会影响原始对象。
- 当你对不可变类型进行修改操作时,会返回修改过的内容并需要由变量接收,否则当你重新查看原变量名时发现内容并没有更新
# 数字类型(int/float)
num1 = 1
num1.__add__(2)
print(num1) # 1
num1 = 1
print(num1, id(num1)) # 1 2308214751472
num1 = num1.__add__(2)
# 需要将其重新赋值,相加的操作才可以实现
# 当重新赋值,那变量num1的原值1将会被垃圾回收清除,重新开辟内存地址存放变量num1的新值3
print(num1, id(num1)) # 3 2308214751536
# 字符串(str)
str1 = '@run@'
str1.strip('@')
print(str1) # @run@
str1 = '@run@'
print(str1, id(str1)) # @run@ 1737672301872
str1 = str1.strip('@')
print(str1, id(str1)) # run 1737672302000
# 布尔类型(bool)
bool1 = True
print(id(bool1)) # 140710865619816
bool1 = False
print(id(bool1)) # 140710865619848
【三】特殊类型:元组类型Tuple
-
在 Python 中,元组(tuple)是不可变(immutable)类型。这意味着一旦创建了元组,就不能在原地修改其内容,包括添加、删除或修改元组中的元素。
-
以下是一个示例:
-
pythonCopy codemy_tuple = (1, 2, 3) # 尝试修改元组,这会引发 TypeError # 元组是不可变的 my_tuple[0] = 10 # 错误,引发 TypeError
-
由于元组是不可变的,你无法对其进行原地修改。如果你需要对元组进行类似修改的操作,你通常需要创建一个新的元组。
-
需要注意的是,元组的不可变性仅涉及到元组自身的内容。如果元组包含可变对象(如列表),那么这些可变对象的内容是可以被修改的。但是,元组本身的结构(元素的数量和顺序)是不可变的。
-
tup1 = (1, 2, 3, [4, 5]) print(id(tup1)) # 1658887470944 tup1[3].append(6) print(tup1) # (1, 2, 3, [4, 5, 6]) print(id(tup1)) # 1658887470944
【四】相较于其他语言Python的参数传递区别
- 严格意义上来说,Python既不是值传递,也不是引用传递,python是自己的传递方式
- 规则是:
- 如果传递的是不可变类型,在函数中修改,就不会影响原来的变量
- 如果传递的是可变数据类型,在函数中修改,不会影响原来的变量,修改,而不是重新赋值
Python和C语言
- Python 和 C 语言在参数传递方面有一些重要的区别,主要体现在函数调用时参数是如何传递的。下面是 Python 和 C 语言值传递的主要区别:
1. 值传递和引用传递:
-
C 语言: C 语言采用的是值传递(pass by value)。在函数调用时,将实参的值传递给函数的形参。这意味着函数内对形参的修改不会影响到实参。
cCopy code#include <stdio.h> void modifyValue(int x) { x = 10; } int main() { int num = 5; modifyValue(num); printf("%d\n", num); // 输出: 5 return 0; }
-
Python: Python 采用的是对象引用传递(pass by object reference)。在函数调用时,将对象引用传递给函数的形参。这意味着如果在函数内部修改了可变对象(例如列表),会影响到实参;但对于不可变对象(例如整数、字符串),函数内的修改不会影响到实参。
pythonCopy codedef modify_value(lst): lst.append(4) my_list = [1, 2, 3] modify_value(my_list) print(my_list) # 输出: [1, 2, 3, 4] def modify_number(x): x = 10 my_number = 5 modify_number(my_number) print(my_number) # 输出: 5
2. 对象的可变性:
- C 语言: C 中的基本数据类型是不可变的,而数组可以修改,但修改数组的内容不会影响原数组。
- Python: Python 中一切皆对象,有可变对象(如列表、字典)和不可变对象(如整数、字符串)之分。函数内对可变对象的修改会影响到原对象,而对不可变对象的修改则不会影响原对象。
3. 内存管理:
- C 语言: 在 C 中,需要手动管理内存,通过指针等进行内存的申请和释放。
- Python: Python 具有自动的垃圾回收机制,无需手动管理内存。这意味着在 Python 中,你通常不需要担心内存的申请和释放问题。
总体而言,虽然 Python 使用的是对象引用传递,但在实际使用中,理解对象的可变性和不可变性,以及对于可变对象和不可变对象在函数调用中的行为,是更为重要的方面。
Python和Java
Python 和 Java 在参数传递方面有一些重要的区别,主要涉及到参数是如何传递给函数或方法的。下面是 Python 和 Java 传递的主要区别:
1. 值传递和引用传递:
-
Java: Java 使用值传递(pass by value)。在函数调用时,将实际参数的值传递给形式参数。这意味着函数内对形式参数的修改不会影响到实际参数。
javaCopy codepublic class Example { public static void modifyValue(int x) { x = 10; } public static void main(String[] args) { int num = 5; modifyValue(num); System.out.println(num); // 输出: 5 } }
-
Python: Python 使用对象引用传递(pass by object reference)。在函数调用时,将对象引用传递给函数的形参。这意味着如果在函数内部修改了可变对象,会影响到实际参数;但对于不可变对象,函数内的修改不会影响到实际参数。
pythonCopy codedef modify_value(lst): lst.append(4) my_list = [1, 2, 3] modify_value(my_list) print(my_list) # 输出: [1, 2, 3, 4] def modify_number(x): x = 10 my_number = 5 modify_number(my_number) print(my_number) # 输出: 5
2. 对象的可变性:
- Java: Java 中的基本数据类型是不可变的,而对象引用也是传值的。如果传递的是对象引用,修改对象内部的状态会影响原对象。
- Python: Python 中有可变对象(如列表、字典)和不可变对象(如整数、字符串)之分。函数内对可变对象的修改会影响到原对象,而对不可变对象的修改则不会影响原对象。
3. 异常处理:
- Java: 在 Java 中,异常是对象,通过引用传递。如果在方法内部捕获并修改异常,对原始调用方不会产生影响。
- Python: 在 Python 中,异常也是对象,但是异常传递的是引用的副本。如果在函数内捕获并修改异常,对原始调用方也会产生影响。
总体而言,了解参数传递的机制以及对象的可变性和不可变性是理解 Python 和 Java 在这方面的区别的关键。在实际编程中,对于传递给函数的参数如何影响原始数据的理解是非常重要的。