示例:计数器
除了ID生成器之外,计数器也是构建应用程序时必不可少的组件之一,如对于网站的访客数量、用户执行某个操作的次数、某首歌或者某个视频的播放量、论坛帖子的回复数量等,记录这些信息都需要用到计数器。实际上,计数器在互联网中几乎无处不在,因此如何简单、高效地实现计数器一直都是构建应用程序时经常会遇到的一个问题。
代码清单2-7 展示了一个计数器实现,这个程序把计数器的值存储在一个字符串键里面,并通过INCRBY命令和DECRBY命令对计数器的值执行加法操作和减法操作,在需要时,用户还可以通过调用GETSET方法来清零计数器并取得清零之前的旧值。
代码清单2-7 使用字符串键实现的计数器:/string/counter.py
class Counter:
def__init__(self, client, key): self.client = client self.key = key defincrease(self, n=1): """ 将计数器的值加上n,然后返回计数器当前的值。 如果用户没有显式地指定n,那么将计数器的值加上1 """ returnself.client.incr(self.key, n) defdecrease(self, n=1): """ 将计数器的值减去n,然后返回计数器当前的值。 如果用户没有显式地指定n,那么将计数器的值减去1 """ returnself.client.decr(self.key, n) defget(self): """ 返回计数器当前的值 """ # 尝试获取计数器当前的值 value = self.client.get(self.key) # 如果计数器并不存在,那么返回0作为计数器的默认值 ifvalue isNone: return0 else: # 因为redis-py的get()方法返回的是字符串值,所以这里需要使用int()函数将字 # 符串格式的数字转换为真正的数字类型,比如将"10"转换为10 returnint(value) defreset(self): """ 清零计数器,并返回计数器在被清零之前的值 """ old_value = self.client.getset(self.key, 0) # 如果计数器之前并不存在,那么返回0作为它的旧值 ifold_value isNone: return0 else: # 与redis-py的get()方法一样,getset()方法返回的也是字符串值,所以程序在 # 将计数器的旧值返回给调用者之前,需要先将它转换成真正的数字 returnint(old_value)
在这个程序中,increase()方法和decrease()方法在定义时都使用了Python的参数默认值特性:
defincrease(self, n=1): defdecrease(self, n=1):
以上定义表明,如果用户直接以无参数的方式调用increase()或者decrease(),那么参数n的值将会被设置为1。
在设置了参数n之后,increase()方法和decrease()方法会分别调用INCRBY命令和DECRBY命令,根据参数n的值,对给定的键执行加法或减法操作:
# increase()方法 returnself.client.incr(self.key, n) # decrease()方法 return self.client.decr(self.key, n)
注意,increase()方法在内部调用的是incr()方法而不是incrby()方法,并且decrease()方法在内部调用的也是decr()方法而不是decrby()方法,这是因为在redis-py客户端中,INCR命令和INCRBY命令都是由incr()方法负责执行的:
●如果用户在调用incr()方法时没有给定增量,那么incr()方法就默认用户指定的增量为1,并执行INCR命令。
●如果用户在调用incr()方法时给定了增量,那么incr()方法就会执行INCRBY命令,并根据给定的增量执行加法操作。
decr()方法的情况也与此类似,只是被调用的命令变成了DECR命令和DECRBY命令。
以下代码展示了这个计数器的使用方法:
>>> fromredisimportRedis >>> fromcounterimportCounter >>> client = Redis(decode_responses=True) >>> counter = Counter(client, "counter::page_view") >>> counter.increase() # 将计数器的值加上1 1 >>> counter.increase() # 将计数器的值加上1 2 >>> counter.increase(10) # 将计数器的值加上10 12 >>> counter.decrease() # 将计数器的值减去1 11 >>> counter.decrease(5) # 将计数器的值减去5 6 >>> counter.reset() # 重置计数器,并返回旧值 6 >>> counter.get() # 返回计数器当前的值 0