Python中级之可变数据类型和不可变数据类型

发布时间 2023-12-06 17:40:07作者: Lea4ning

【一】可变数据类型

  • 对于可变类型(如字典、列表、集合),在函数中修改参数会影响原始对象。
  • 当你对于可变类型进行修改操作,并不会返回内容,而是将原本的内容进行了更新
# 字典(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是自己的传递方式
  • 规则是:
    • 如果传递的是不可变类型,在函数中修改,就不会影响原来的变量
    • 如果传递的是可变数据类型,在函数中修改,不会影响原来的变量,修改,而不是重新赋值

img

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 在这方面的区别的关键。在实际编程中,对于传递给函数的参数如何影响原始数据的理解是非常重要的。