------------------------------匿名函数---玩法==补充:垃圾回收机制

Lambda函数可以具有任意数量的参数,但只能有一个表达式。该表达式将被求值并返回

f = lambda x, y: x ** y  # 返回x的y次方
f1 = lambda x: x + 1     # 返回x+

我们通常使用Lambda函数作为高阶函数的参数,该函数以其他函数作为参数。匿名函数与内置函数(如 filter(), map() 等)一起使用

# filter(function or None, iterable) --> filter object
# 过滤器,返回一个迭代器保留那些func(item)之后为True的项,
# 如果function为none,返回为True的项
# 例如:filter(lambda n:n>5,range(10))
# 派生:map(lambda n:n*2,range(10))
# 派生:[abs(i) : for i in range(10)]
# 派生:functools.reduce(lambda x,y:x*y,range(10))
filter()
# map(func, *iterables) --> map object
# 制作一个迭代器,从每个可迭代对象获取参数用来计算函数。
# 当短迭代耗尽的时候停止
# 把一个或多个迭代器当成参数喂给函数,返回一个函数运行后的迭代器。
map()  


import functools
r = functools.reduce(lambda x, y: x * y, range(1, 5)) # 1234
# 用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,
# 得到的结果再与第三个数据用 function 函数运算,最后得到一个结果
print(r) #24



内存管理


综上所述,

float对象在创建对象时会把为其开辟内存并初始化引用计数器为1,然后将其加入到名为 refchain 的双向链表中;

float对象在增加引用时,会执行 Py_INCREF在内部会让引用计数器+1;

最后执行销毁float对象时,会先判断float内部free_list中缓存的个数,如果已达到300个,则直接在内存中销毁,

否则不会真正销毁而是加入free_list单链表中,以后后续对象使用,销毁动作的最后再在refchain中移除即可。 


垃圾回收机制


引用计数变为0导致垃圾回收机制的例子:

class DictA(dict):
    def __del__(self):
        print("DictA被回收")


class DictB(dict):
    def __del__(self):
        print("DictB被回收")


a = DictA()
b = DictB()

a = 1
b = 1
# a=1;b=1导致引用计数变为0,立即触发垃圾回收机制,a,b会在“ok”之前被回收
print("ok")

# 输出结果:
"""
DictA被回收
DictB被回收
ok
"""

当对象的引用计数器为0时,就会被销毁并释放内存。而实际上他不是这么的简单粗暴。

因为反复的创建和销毁会使程序的执行效率变低。Python中引入了“缓存机制”。
例如:引用计数器为0时,不会真正销毁对象,而是将他放到一个名为 free_list 的链表中,之后会再创建对象时不会在重新开辟内存,而是在free_list中将之前的对象来并重置内部的值来使用

float类型、int类型、str类型、list类型、tuple类型、dict类型分别有自己的链表存放垃圾对象。

循环引用导致不能立即执行垃圾回收机制的例子

class DictA(dict):
    def __del__(self):
        print("DictA被回收")


class DictB(dict):
    def __del__(self):
        print("DictB被回收")


a = DictA()
b = DictB()

a['xxx'] = b
b['yyy'] = a

a = 1
b = 1
# a=1;b=1不能使引用计数变为0,因为循环引用了,a,b会在打印“ok”之后被回收
print("ok")

# 输出结果:
"""
ok
DictA被回收
DictB被回收
"""

引用计数为主,标记清除和分代回收为辅

python内部维护一个 refchain的“环状双向链表”, 创建的所有对象放在该链表中。

对象内部有该对象的引用计数,当引用计数变为0,触发python的垃圾回收,将其放入缓存

这样导致一个问题,循环引用永远不会被回收。为了解决这个问题,python引入三个“环状双向链表”

0代,1代,2代。 创建对象时把可能发生循环引用的可变对象放入0代。当0代数量达到700时,

python对其进行标记清除,引用计数-1,减1为0的进行回收。不为0的放入1代。

依次类推。0代回收10次触发1代回收,1代回收10次触发2代回收。

https://www.bilibili.com/video/BV1ok4y1B7eE?p=1

原文地址:https://www.cnblogs.com/staff/p/9272003.html