Python中的冷知识

可变对象与不可变对象

为了理解对象的可变与不可变, 首先理解什么是变量, 什么是对象

在 Python 中,变量都是指针;指针的内存空间与数据类型无关,其内存空间保存了指向数据的内存地址。
在 Python 中,一切皆对象,其主要由以下部分组成:

  • identity(ID):标识对象的“内存地址”,可使用 id(obj) 获取(唯一标识)
  • type(类型):标识对象的“类型”,可使用 type(obj) 获取
  • value(值):标识对象的“值”,可使用 print(obj) 获取

注意: 对象的本质是一个内存块
注意: 变量无类型,对象有类型;变量位于栈内存,对象位于堆内存。

变量指向一个对象, 可变不可变指的是变量指向的对象是否可变, 在程序中的表现就是, 不可变对象修改变量值时由于其对象不可变,那么需重新开辟内存空间储存新值后在赋予给变量, 而可变对象修改变量时,是直接在原来内存中修改的.

不可变对象

定义: 不可变对象是指,一个对象所指向的地址上值是不能修改的. 如果你修改了这个对象的值,那么它指向的地址就改变了,相当于你把这个对象指向的值复制出来一份,然后做了修改后存到另一个地址上了

不可变对象包括:bool(布尔)、int(整数)、float(浮点数)、str(字符串)、tuple(元组)、frozenset(不可变集合),具有以下特性:

  • 可hash(不可变长度)
  • 不支持新增/删除/修改
  • 支持查询

可变对象

定义: 可变对象是指,一个对象在不改变其所指向的地址的前提下,可以修改其所指向的地址中的值

可变对象包括:list(列表)、set(集合)、dict(字典),具有以下特性:

  • 不可 hash(可变长度)
  • 支持新增/删除/修改/查询

所以, 可变对象与不可变对象的区别就是, 改变其值后使用id()查看内存地址是否改变

Python参数是值传递还是引用传递

在 Python 参数传递中,不存在所谓值传递和引用传递的区分,其本质都是拷贝对象的引用(指针)传递。

def func1(a):
    print(id(a))
    a = 654321
    print(id(a))
b = 123456
print(id(b))
func1(b)

# 1921163820176
# 1921163820176
# 1921163819760

def func2(a):
    print(id(a))
    a.append(2)
    print(id(a))
c = [1]
print(id(c))
func2(c)

# 1921163742528
# 1921163742528
# 1921163742528

从以上来看, 在Python中不管是可变对象还是不可变对象, 在传递参数时都是引用传递. 区别是传递给函数后, 改变其值后, 可变对象的地址不变, 而不可变对象的地址改变. 这也是为什么说 Python里所有的数据类型都是对象(python中一切皆为对象)

这里需和其他编程语言做个区别, 其他编程语言是分为值传递和引用传递的. 值传递是将其值复制一份传给函数, 其内存地址是改变的.

Python中小整数声明时值相同时地址也相同

Python中对于小的整数存在一个缓存池。为了避免因创建相同的值而重复申请内存空间所带来的效率问题, Python解释器会在启动时创建出小整数池,范围是[-5,256],该范围内的小整数对象是全局解释器范围内被重复使用,永远不会被垃圾回收机制回收。

>>> a = 1
>>> b = 2
>>> id(a)
2708248357168
>>> id(b)
2708248357200
>>> a = a+1
>>> id(a)
2708248357200

>>> m = 123456789
>>> n = 123456789
>>> m is n
False
>>> id(m)
2004539308784
>>> id(n)
2004539309200

在函数内操作函数外的变量

a = 1
def change():
    x = 10 + a
    print(x)

change() # 正常打印出11
print(a)
a = 1
def change():
    a = 10 + a
    print(a)

change() # UnboundLocalError: local variable 'a' referenced before assignment
print(a)

注意: 如果我们想 在函数中修改函数外变量 就会出现问题, 这是因为,a = 10 + a是一条赋值语句,Python解释器会将 a 认作局部变量,所以 10 + a 因为 a 这个局部变量还没有定义,而抛出这样的错误。

知识点: 当在函数中调用未被定义的变量时, 先会在local局部变量中搜索该变量名, 如果找不到会向上搜索, 再查不到就在global中搜索.

此处评论已关闭