Python 数据类型,是否可变、可哈希

可变性

  • 可变对象:可以在对象创建后修改其内容(值)。
  • 不可变对象:对象一旦创建后,其内容不能再被修改。

常见的可变和不可变类型:

  • 可变对象
    • 列表 (list)
    • 字典 (dict)
    • 集合 (set)
    • 用户自定义的类实例(默认情况下)
  • 不可变对象
    • 整数 (int)
    • 浮点数 (float)
    • 字符串 (str)
    • 元组 (tuple)
    • 布尔值 (bool)
    • frozenset (frozenset)

例子:

# 可变对象:列表
lst = [1, 2, 3]
lst[0] = 100  # 修改成功

# 不可变对象:元组
tup = (1, 2, 3)
# tup[0] = 100  # 这一行会报错,因为元组不可修改

与引用的关系:

  • 可变对象通过引用传递时,如果外部函数对对象进行修改,则在原作用域中对象的内容也会改变。
  • 不可变对象通过引用传递时,由于内容不能更改,传递的是一个新的对象引用。

是否可哈希

  • 可哈希对象:对象具有一个固定的哈希值,可以通过调用 hash() 函数来获得,并且它们的内容在对象生命周期内不能改变。
    • 不可变对象:intfloatstrtuple(如果所有元素都是可哈希的)、frozenset
    • 这些对象通常可以作为 字典的键集合的元素
  • 不可哈希对象:没有哈希值,通常因为对象是可变的,其内容可能随时更改,从而使哈希值不再一致。
    • 可变对象:listdictset
    • 这些对象不能作为 字典的键集合的元素
# 可哈希对象
print(hash("hello"))  # 字符串是不可变的,可哈希
print(hash((1, 2, 3)))  # 元组是不可变的,可哈希

# 不可哈希对象
# print(hash([1, 2, 3]))  # 列表是可变的,无法哈希
# print(hash({'a': 1}))   # 字典是可变的,无法哈希
# print(hash({1, 2, 3}))  # 集合是可变的,无法哈希

哈希性与可变性的关系:

  • 可哈希对象通常是不可变对象,因为只有不可变对象才能保证哈希值在其生命周期内不会改变。
  • 不可哈希对象往往是可变对象,因为其内容可以改变,哈希值会随之发生变化。

Python 的参数传递机制

Python 中的参数传递既不是值传递也不是引用传递,而是对象的引用传递。这意味着函数接收到的是对象的引用,而不是对象本身的拷贝。因此,如果对象是可变的,修改它会影响到调用者范围内的对象。

具体的表现可以根据对象的可变性来区分:

  • 可变对象:当你将可变对象(如 listdictset)作为参数传递到函数时,函数内部的修改会影响到外部的变量,因为函数操作的是对象的引用,即它们指向同一个对象。
  • 不可变对象:当你将不可变对象(如 intfloatstrtupleboolfrozenset)作为参数传递到函数时,任何修改都会创建一个新的对象,函数内部的修改不会影响外部的变量。

可变对象和不可变对象在引用传递中的表现

# 可变对象(列表)
def modify_list(lst):
    lst.append(4)

my_list = [1, 2, 3]
modify_list(my_list)
print(my_list)  # 输出: [1, 2, 3, 4]

在这个例子中,my_list 是一个可变对象(列表)。当我们把它传递给 modify_list 函数时,函数内部对列表的修改(append 操作)会直接影响外部的 my_list,因为它们引用的是同一个对象。

# 可变对象(字典)
def modify_dict(d):
    d['new_key'] = 'new_value'

my_dict = {'key': 'value'}
modify_dict(my_dict)
print(my_dict)  # 输出: {'key': 'value', 'new_key': 'new_value'}

这里的 my_dict 是一个字典(可变对象),传递到函数 modify_dict 后,函数内部对字典的修改直接反映在外部的 my_dict 上。

# 不可变对象(字符串)
def modify_string(s):
    s = "new string"  # 试图修改传入的字符串

my_str = "old string"
modify_string(my_str)
print(my_str)  # 输出: "old string"

这里的 my_str 是一个不可变对象(字符串)。当我们把它传递给 modify_string 函数时,函数内部的赋值操作创建了一个新的字符串对象,my_str 本身并没有被修改,外部的变量仍然保持原样。

# 不可变对象(整数)
def modify_number(n):
    n += 10  # 修改传入的数值

my_num = 5
modify_number(my_num)
print(my_num)  # 输出: 5

my_num 是一个不可变对象(整数)。即使在 modify_number 函数内部对其进行了修改,这也不会影响外部的 my_num。在函数内部,修改操作实际上生成了一个新的整数对象,而原来的 my_num 仍指向原来的值。


总结

可变性直接决定了对象是否可以被哈希。如果对象是可变的,它的值可以在生命周期中改变,导致哈希值也不固定,因此可变对象不可哈希

可哈希对象通常是不可变的,它们具有稳定的哈希值,并且可以用作 字典的键集合的元素

引用使得多个变量可以指向同一个对象。对于可变对象,多个引用之间会互相影响。而对于不可变对象,修改操作实际上是在创建一个新的对象,原有的引用保持不变。

实际工作中:

哈希性的要求决定了对象的使用场景。例如,字典的键集合的元素必须是可哈希的对象,所以必须是不可变的。

可变对象可以通过引用进行修改,因此在编写代码时要小心引用的共享,避免意外的修改。如果不希望对象被意外修改,考虑使用不可变对象或创建对象副本。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值