几个必知的python小知识

本文介绍了Python中的可变与不可变对象,浅拷贝与深拷贝的区别,以及`==`和`is`的用法。深入探讨了`isinstance()`与`type()`的差异,并讨论了垃圾回收机制和内存泄漏问题。最后,讲解了函数默认参数的陷阱。文章适合Python初学者和进阶者阅读,有助于理解Python内存管理和对象行为。
摘要由CSDN通过智能技术生成

1.可变对象 和 不可变对象

可变对象

对象内容可修改。

  • list
  • dict
  • set

不可变对象

对象内容不可被修改,所在内存单元被固定好了,变量初始赋值为一个不可变对象,重新对变量赋值 实际上是 变量指向了另一块内存单元(简单来说:赋值即引用)。

  • str
  • tuple
  • int,long,float,complex

2. 浅拷贝 和 深拷贝

浅拷贝

浅层的对象被复制一份,内部可变对象的内存单元 未改变
两者中可变对象的修改会相互影响。(简单说就是浅拷贝 只拷贝了引用

浅拷贝操作:

  • [:]
  • copy.copy()
a = [1,2,[3,4]]
b = a[:]
b[2][0] = 5
print(a) # [1,2,[5,4]]
print(b) # [1,2,[5,4]]

切片操作

python 中支持切片操作的对象有:

  • str
  • tuple
  • list

深拷贝

完美拷贝了一份,可变对象被重新创建,可变对象内存单元 变了,两者修改不影响。

深拷贝操作:

  • copy.deepcopy()
import copy
a = a = [1,2,[3,4]]
b = copy.deepcopy(a)
b[2][0] = 5
print(a) # [1,2,[3,4]]
print(b) # [1,2,[5,4]] 

3. == 和 is

import copy
a = [1,2,3,[4,5]]
b = a[:] # 等价于b = copy.copy(a)
c = copy.deepcopy(a)
a[-1] == b[-1]  # True
a[-1] is c[-1] # False,等价于id(a[-1]) == id(c[-1])
  • == 只比较是否相等
  • is 比较所在内存单元是否一样(是不是同一个东西)

4. isinstance 和 type

  • isinstance() 会认为子类是一种父类类型,考虑继承关系
  • type() 不会认为子类是一种父类类型,不考虑继承关系;

判断是否是同类型一般使用isinstance(object, classinfo)

5. 垃圾回收 和 内存泄漏

垃圾回收

基于:

  • 引用计数
  • 垃圾收集器(可解决循环引用问题)

内存泄漏

可能发生内存泄漏的场景:循环引用。
只有容器对象才会发生循环引用:如class,list,dict,set,deque

class A(object):
    def __init__(self):
        self.data = [x for x in range(100000)]
        self.child = None

    def __del__(self):
        pass


def cycle_ref1():
    a = A()
    b = A()
    a.child = b
    b.child = a

# 运行后,打开任务管理器可以看到该python程序所占内存飙升
import time
while True:
    time.sleep(0.5)
    cycle_ref1()

解决方法:
被循环引用的对象不自定义__del__(这种情况,我测试了一下,垃圾自动回收效果不明显{几乎没有!!??},所以还是自己处理比较靠谱。。),若自定义了__del__,在适当的时机解除引用:

def cycle_ref2():
    a = A()
    b = A()
    a.child = b
    b.child = a

    a.child = None
    b.child = None

使用弱引用模块weakref中的weakref.proxy()来引用:

import weakref
def cycle_ref3():
    a = A()
    b = A()
    a.child = weakref.proxy(b)
    b.child = weakref.proxy(a)

详见:Python垃圾回收与内存泄露

6. 函数默认值只执行一次

'''
 函数默认值只会执行一次。
 这条规则在默认值为可变对象(列表、字典以及大多数类实例)时很重要。
'''
def appendList1(x,L = []):
    L.append(x)
    return L

def appendList2(x,L = None):
    if L is None:
        L = []
    L.append(x)
    return L

if __name__ =='__main__':
    print(appendList1(1))
    print(appendList1(2))
    print(appendList1(3))

    print('*'*20)
    print(appendList2(1))
    print(appendList2(2))
    print(appendList2(3))

输出:

[1]
[1, 2]
[1, 2, 3]
********************
[1]
[2]
[3]

不足之处欢迎批评指正!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Leo Bliss

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

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

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

打赏作者

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

抵扣说明:

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

余额充值