这是一个装饰器用的函数,参数固定下来,可以认为是有参,也可以认为是无参
最大缓存128条,改成none就不受限制
缓存其实把有限空间内最长用的保存下来就可以了,缓存一般是把最常用的数据放到内存中,要的时候直接去找
lru是最近最少使用的,这是一种策略,如果缓存不够,优先把最近最少使用 的清理掉,如果够就暂时不清理
如果最大长度为none就禁用LRU功能,就可以无限制增长了,不清理了,当maxsize是2的幂时,2,4,8,16
其实就是告诉你容量是乘倍往外翻,由2变4,由4变8,成倍的翻,(不够再说,再翻倍空间)
如果一个数据只增不减,你放多大数据都没有用
假定这样执行就是特别耗时的
但是函数却平凡使用,但是这个函数只要给定一个x,得到你期望的值
给定x就一定可以得到y
给-4出4,不会出-2,调用无数次,只要送-4就出4
这样叫幂等性,由幂等性的东西才需要缓存
‘
直接告诉你不能这么使用的
带参装饰器,里面参数用缺省值
第一个3感觉就只等了3秒
已经执行过了一次,再次执行的时候就可以用缓存
前面是算了一段时间,后面是前面算过一次了
x=4是已经算过了,x=4虽然本质上是一样的,但是实际上是不一样的
本身是个耗时的,它就把你的结果保存下来,如果下次函数调用方式是一样的,就直接从cache中提取结果给你,而这个提取速度是很快的
这种调用方式是不一样的
现在用位置传参方式和关键字传参方式是两种不一样的传参方式
修改一下,第一次没法缓存,用下面几种方法调用一下
从本质来讲这些算出来的结果都是一样的
5种都重新算了,这5种方式在它眼里都是不一样的
再次执行瞬间全有,因为每一种形式都覆盖了,缓存到了cache中
、缓冲和缓存不一样,缓冲是缓冲地带的意思,一般是队列,缓存的目的是为了查询快,因为每次查询耗时久,就把这些数据放到缓存当中
从磁盘中拿太慢了,拿一下需要5秒,这些也就适合放在缓存中,关键是放在缓存中的前提
什么情况下应该缓存
比如一小时内发送3过去,他这一小时就返回4,再小时内,如果请求代价太高,等的时间太长,在这个一小时内,缓存是有意义的
但是如果一个小时就访问一次,是不需要缓存的
如果发现在一段时间频繁使用,数据拿一次不容易,但是用的人很多,就可以去使用,缓存是有时效的
、如果type是true就不是这样的了
都用缺省值,直接调用即可
加个时间,用这种方式是加不进去了,就没有追加效果了,因为没有在函数体内追加,是直接去缓存里问做过没有
估计是列表出的事情,因为列表不可hash
不可hash是set,字典结构,因为是查询,所以用的肯定是字典
实际上都需要把实参的部分组成key
这边出问题,是要在字典中把你传的参数要组织起来
make_key双击一下
传入的位置参数,和关键字传参,是用位置参数和关键字传参合起来做为一个key,后面type先不管
查看make_key怎么做的
如果位置参数由,直接把位置参数作为key,这个key其实就是后面字典要里的kv对的k
args刚才我们传了[0],这个就不能作为key,列表不可hash
传进来不能是有不可哈希的,key只能是个tuple(列表元组,set,字典,只能用tuple),因为其他类型都不能用,要想作为字典的key就必须用tuple(*args就是(1,1,2,3)这样的)
下面是元组+=
item拿到的是一个个二元组,凑成 了一个长元素
就类似这样
变成这样
对于不可变类型+=是,返回新的元组
再加一个object ,是区分位置和关键字的,把这个一加就相当于分界线了
kwds讲完了,下面是typed,从args里面把类型拿出来,把类型凑到元组里面去了
类似写成这样
把位置传参的所有类型拿到之后,用元组包起来,把这个元组加到前面去,就把类型追加上去了
把字典中的所有值的类型也取出来了,也变成元组追加上去,就是把你传进来的值把类型取出来,然后追加到元组里面
如果是快速类型则直接返回这个类型即可
最后这个,这个能帮助我们构建出key
ctrl+左键点击查看这个
本质上这个是个列表
这个写法还是从tup复制到self,一般写在右边切片构造它
从tup构造出self
刚才通过传参的方式,传入一个元素为0的列表,[0]
**元素为0的列表走到这一步还能继续吗,就出问题了
**
再makekey中没有任何问题,把keyreturn的时候传给 hashedseq,key通过它传到tup
凡是看到类的时候,self可以不管,可以认为init这个函数是两参,第一个参数是元组tup
元组传到这
这个key交给tup,这句话把元组进行hash,但是元组里出现列表参数,就不可hash,所以问题出在这里
缺省值根本没有参与到key当中去
缺省值不要实际是跟上面直接调用是一样的
无参等于是空元组
这是keyword,需要拼一个object
关键字传参首先就要给你做间隔
如果这个元组可hash这个key就做成了
就会把哈希值扔回去
这个类会造成一个对象,字符串有字符串对象,列表有很多列表对象
使用这个类,用key这个元组构造一个新的对象出来,对象类型是_HashedSeq,
但是_HashedSeq这个对象构造的时候要拿到一个哈希值
这个哈希值放到对象的一个属性上,hashvalue
内建hash函数,是传的默认值,前面是标识符
这个函数,表面是个函数,但实际是个标识符,标识符被调用就调用标识符后面的函数对象,这个对象指的是hash函数
这个上面的hash其实是个局部变量,后面的hash则是缺省值
所以下面的hash指代上面的
x的类型就是_hashedseq
询问xhsh的时候,就会问x这个对象有没有hash方法
这个hash方法就会找hash(tup)这个值
就把self.hashvalue这个值返回回去,
x是对这样的包装,这个东西是可以哈希的
!在这里插入图片描述
把元组拿进来做了个哈希值,然后返回一个新的对象
这个对象把hash值返回了
用的还是这个 哈希值
当x hash找这个值
这个值来自于元组求的哈希值
说到底这个东西可以当做没有,就是里面的元组进行hash,把hash值保存下来,然后要的时候还是这个元组的hash值
说白了就是把元组全部hash,然后给你返回一个新对象。新对象的hash是什么,哈希值就是算好的原来元组的哈希值
如果调用内建函数,python就会问这个实例有没有模式方法
list也有hash但是返回的是none
现在如果要对一个对象求哈希值,就是要去这个对象定义里面,找有没有hash这个方法,如果有这个方法就去里面拿值
如果是1,你的hash值就永远是1
但是如果返回这个,这个hash值就是1234的哈希值
加上列表,就不能hash了
读源码提升理解能力,是列表还是元组都这么迭代,标准库有很多范例是可以学习的
缺省值这两是一样
颠倒过来也不一样,因为遍历的时候就按照你这个顺序遍历,组成的元组不一样
下划线是有意义的,就是告诉你不是轻易给你用的
函数封装是尽量通过传参传进来,有缺省值就用缺省值,没有就参数传进去
传一个元组,字典,type=false
这个key就是从列表上继承下来,
慢慢追加
后面执行完点击左边的
这样就执行完了,整个程序执行完了,就看不到变量了
但控制台给你打印了
true和false是把类型也追加到后面去了,这几个全都不一样
以前的斐波那契数列是这么写的
算40的时候就很慢
有了缓存就瞬间执行完毕,缓存记录了上一次的计算结果
解析式的问题
使用的前提:
同样的函数参数一定得到同样的结果 ()
函数执行时间很长,且要多次执行(在一段时间内如果要频繁使用,不能忍受执行时间长)
本质是函数调用的参数=》返回值(映射,就是字典,mapping)
缺点:
不支持缓存过期,key无法过期、失效
不支持清除操作(让缓存统一失效没这个功能)
不支持分布式,是一个单机的缓存
使用场景,单机上需要空间换时间的地方,可以用缓存来计算变成快速的查询
习题
类型不对,hash就给你报错了
就是输入的字符串调用的是一个函数,这个函数注册进来的,由一个命令找到一个函数的过程称为路由