Python 基于python操纵redis入门介绍

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Python 基于python操纵redis入门介绍

基于python操纵redis入门介绍

 


测试环境

redis-3.0.7

 

CentOS 6.5-x86_64

 

python 3.3.2

 

基于Python操作Redis

Redis客户端实例是线程安全的,可以直接将Redis连接实例设置为一个全局变量,直接使用。如果需要另一个Redis实例,就需要重新创建redis连接实例来获取一个新的连接

 

示例

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

 

import redis

 

if __name__ == '__main__':

   r = redis.StrictRedis(host='192.168.1.103', port=6379, db='0')

   result = r.set('name', 'shouke')  # 存储键-

   print('result of set: %s' % result)

 

   r.set('hobby', 'music')

 

   name = r.get('name')  # 获取键“name”对应的值

   print('name: %s' % name)

 

   keys = r.keys()  # 获取所有键

   print('keys: %s' % keys)

 

   dbsize = r.dbsize() # redis数据库包的记录数(key的数量)

   print('dbsize: %s' % dbsize)

 

   result = r.delete('hobby')  # 根据指定的键,删除指定键-

   print('result of delete: %s' % result)

 

   result = r.save()  # 执行检查点操作,将数据写回磁盘。保存时阻塞

   print('result of save: %s' % result)

 

   hobby = r.get('hobby')

   print('hobby: %s' % hobby)

 

   name = r['name']   # 获取键“name”对应的值

   print('name: %s' % name)

 

   result = r.flushdb()   # 清空数据当前库中的所有数据

   print('result of flushdb: %s' % result)

 

   print('dbsize: %s' % r.dbsize())

结论:

result of set: True

name: b'shouke'

keys: [b'name', b'hobby']

dbsize: 2

result of delete: 1

result of save: True

hobby: None

name: b'shouke'

result of flushdb: True

dbsize: 0

 

连接池

redis-py使用连接池来关联连接到Redis服务器的连接。默认的,每个Redis实例会按顺序创建自己的连接池。可以重写该行为,如下:

pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

r = redis.Redis(connection_pool=pool)

 

连接

连接池管理一系列的连接实例。redis-py拥有两种类型的连接。默认的,Connection基于普通TCP socket的连接,UnixDomainSocketConnection允许运行在相同设备的客户端作为服务器,通过一个unix domain socket进行连接,使用示例如下:

r = redis.Redis(unix_socket_path='/tmp/redis.sock')

 

注:确保在redis.conf文件中定义了unixsocket参数(默认的,该参数已被注释掉)

 

也可以创建自己的Connection子类

pool = redis.ConnectionPool(connection_class=YourConnectionClass,

                               your_arg='...', ...)

 

解析器Parsers

redis-py有两种paser类,PythonParserHiredisParser。默认的,redis-py会试图使用HiredisParser如果已安装hiredis模块,且否则使用PythonParser。使用Hiredis可以大大提高解析返回结果的速度。

 

 

响应回调

客户端类使用了一系列的回调来转换Redis响应为适当的python类型。这类回调函数在Redis客户端类一个名叫RESPONSE_CALLBACKS的字典中进行了定义了。

 

使用set_response_call方法可以为每个实例添加客户端回调。该方法接收两个参数:命令行名称和回调。这种方式添加的回调函数仅在被添加的实例有效。如果想定义或重写全局的回调函数,可以定一个Redis的子类并添加回调用到REDIS_CALLBACKS字典。

 

管道(Pipelines)

Redis类的子类,在单一请求中缓冲发往服务器的多条命令。通过减少往返于服务器和客户端之间TCP包数量,显著的提高分组命令的执行性能。

 

示例

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

   result = r.set('name', 'shouke')

   print(result)

 

   pipe = r.pipeline() # 创建一个管道实例

   result = pipe.set('name2', 'ishouke')

   print(result)

 

   result = pipe.get('name2')

   print(result)

 

   result = pipe.execute()  # 把所有缓冲命令发送到服务器,返回一个列表,包含每个命令的执行结果

   print(result)

 

运行结果:

True

Pipeline>>

Pipeline>>

[True, b'ishouke']

 

注:重复运行的情况下,如果key重复了,redis默认直接覆盖旧值

 

也可以改成如下方式

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   pipe = r.pipeline()

   name2 = []

   result = pipe.set('name', 'shouke').sadd('ishouke', 'name').incr('num').execute()

   print(result)

   print(r.keys())

 

运行结果:

[True, 1, 1]

[b'ishouke', b'name', b'num']

 

incr指定的键不能和saddset中指定的键相同,否则可能报错,类似如下:

redis.exceptions.ResponseError: Command # 3 (INCRBY name2 1) of pipeline caused error:WRONGTYPE Operation against a key holding the wrong kind of value

 

默认的情况下,管道中缓冲的指命令组为一个原子操作,执行

pipe = r.pipeline(transaction=False)   可以禁用这一特性。

 

一个常见的问题:在进行原子事务操作前,需要优先从Redis中获取数据,例如,假设INCR命令不存在,且需要用python编译一个原子版本的INCR

 

一个不成熟的本地实现是先GET值,然后在python中增加它,然后SET值。然而,这并不是一个原子性的,因为多个客户端可以同时做这件事情,每一个客户端都通过GET获取相同的值。

 

WATCH命令提供了在开始一个事务之前监控一个或多个键值的能力。如果开始事务之前,任何一个key的值改变了,整个事务将被取消并抛出一个WatchError。为了完成我们自己客户端的INCR命令,我们可以如下方式实现:

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   result = r.flushdb()

   with r.pipeline() as pipe:

       while 1:

           try:

             # 对序列号的键进行 WATCH

               pipe.watch('OUR-SEQUENCE-KEY')

             # WATCH 执行后,pipeline 被设置成立即执行模式直到我们通知它重新开始缓冲命令这就允许我们获取序列号的值

               current_value = pipe.get('OUR-SEQUENCE-KEY')

               next_value = int(current_value) + 1

 

               pipe.multi() # MULTI 命令把 pipeline 设置成缓冲模式

               pipe.set('OUR-SEQUENCE-KEY', next_value)

               pipe.execute()

               break

           except Exception:

             # 一定是其它客户端在我们开始 WATCH 和执行 pipeline 之间修改了'OUR-SEQUENCE-KEY',最好的选择是重试

               continue

注意:WATCH期间,因为管道必须绑定到一个连接,特别注意,必须调用reset()使得连接返回到连接池。如果管道是作为Context Manager(如上面的例子所示),将会自动调用reset().当然也可以手动显示的调用。

>>> pipe = r.pipeline()

>>> while 1:

...     try:

...         pipe.watch('OUR-SEQUENCE-KEY')

...         ...

...         pipe.execute()

...         break

...     except WatchError:

...         continue

...     finally:

...         pipe.reset()

 

扫描迭代器

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

   for key, value in (('A', '1'), ('B', '2'), ('C', '3')):

       r.set(key, value)

 

   for key in r.scan_iter():

       print(key, r.get(key))

 

运行结果:

b'C' b'3'

b'B' b'2'

b'A' b'1'

 

说明:类似的还有hscan_iter, sscan_iter and zscan_iter等迭代器

 

 

incr命令

示例:

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   r.set('num_increase_continuously', 1)

 

   result = r.get('num_increase_continuously')

   print(result)

 

   result = r.incr('num_increase_continuously')

   print(result)

 

   result = r.incr('num_increase_continuously')

   print(result)

 

   result = r.get('num_increase_continuously')

   print(result)

 

运行结果:

b'1'

2

3

b'3'

 

说明:

incr(self, key, amount=1)根据amount增加key的值,每执行一次增加amount,返回结果为增加后的值,如果key不存在,则key的值被初始化为amount

 

 

sadd指令

 

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

 

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   result = r.sadd('user:user_tb', 'username')

   print('result of sadd username: %s' % result)

 

   result = r.sadd('user:user_tb', 'hobby')

   print('result of sadd hobby: %s' % result)

 

运行结果:

result of sadd username: 1

result of sadd hobby: 1

 

注:

sadd(self, name, *values): 添加到value(s)到集合name

 

sismember指令

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

 

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   r.sadd('user:user_tb', 'username')

   result = r.sismember('user:user_tb', 'username')

   print(result)

 

注:

sismember(self, name, value):判断value是否是name集合的成员,是则返回True,反之False

 

smembers指令

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

 

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   r.sadd('user:user_tb', 'username')

   r.sadd('user:user_tb', 'hobby')

 

   result = r.smembers('user:user_tb')

   print(result)

 

运行结果:

{b'username', b'hobby'}

 

smembers(self, name):返回集合name的所有成员

 

sunion指令

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

 

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   r.sadd('user:user_tb', 'username')

   r.sadd('user:user_tb', 'hobby')

   r.sadd('order:order_goods', 'username')

 

   result = r.sunion('order:order', 'user:user_tb')

   print(result)

 

运行结果:

{b'hobby', b'username'}

 

注:

sunion(self, keys, *args):根据指定的keys返回集合的并集

 

sinter指令

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

 

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   r.sadd('user:user_tb', 'username')

   r.sadd('user:user_tb', 'hobby')

   r.sadd('order:order_goods', 'username')

 

   result = r.sinter( 'order:order_goods', 'user:user_tb')

   print(result)

 

运行结果:

{b'username'}

 

注:

sinter(self, keys, *args):根据指定的keys返,返回集合交集,为空则返回set()

 

 

hset指令

实现散列表的存储

#!/usr/bin/env python

# -*- coding:utf-8 -*-

 

__author__ = 'shouke'

 

import redis

 

if __name__ == '__main__':

   pool = redis.ConnectionPool(host='192.168.1.103', port=6379, db=0)

   r = redis.Redis(connection_pool=pool)

 

   result = r.hset('user:user_tb', 'name', 'shouke')

   print('result of hset: %s' % result)

 

   r.hset('user:user_tb', 'hobby', 'music')

   r.hset('user:user_tb', 'addr', '深圳')

 

   result = r.hincrby('user:user_tb', 'signin', 1)

   print('result of hincrby: %s' % result)

 

   result = r.hincrby('user:user_tb', 'signin', 1)

   print('result of hincrby: %s' % result)

 

   result = r.hgetall('user:user_tb')

   print('result of hgetall: %s' % result)

 

   result = r.hkeys('user:user_tb')

   print('result of hkeys: %s' % result)

 

运行结果:

result of hset: 1

result of hincrby: 1

result of hincrby: 2

result of hgetall: {b'hobby': b'music', b'addr': b'\xe6\xb7\xb1\xe5\x9c\xb3', b'name': b'shouke', b'signin': b'2'}

result of hkeys: [b'name', b'hobby', b'addr', b'signin']

 

注:

hincrby(self, name, key, amount=1):根据amount增加哈希namekey的值,每执行一次就增加amount,返回结果为key增加后的值

 

hset(self, name, key, value):在哈希name中添加键值对key-value,添加成功则返回1,否则返回0

 

hget(self, name, key):返回哈希name中,key的值

 

hgetall(self, name):返回包含哈希键值对(name/value)的字典 pairs"

 

hkeys(self, name):返回哈希name中的key的列表

 

参考连接:

https://pypi.python.org/pypi/redis#downloads

http://debugo.com/python-redis/

 

更多资料烦查看源代码

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
目录
相关文章
|
1月前
|
API 数据安全/隐私保护 开发者
Python自定义异常:从入门到实践的轻松指南
在Python开发中,自定义异常能提升错误处理的精准度与代码可维护性。本文通过银行系统、电商库存等实例,详解如何创建和使用自定义异常,涵盖异常基础、进阶技巧、最佳实践与真实场景应用,助你写出更专业、易调试的代码。
77 0
|
1月前
|
IDE 开发工具 数据安全/隐私保护
Python循环嵌套:从入门到实战的完整指南
循环嵌套是Python中处理多维数据和复杂逻辑的重要工具。本文通过实例讲解嵌套循环的基本用法、常见组合、性能优化技巧及实战应用,帮助开发者掌握其核心思想,避免常见错误,并探索替代方案与进阶方向。
85 0
|
3月前
|
Python
Python字符串格式化利器:f-strings入门指南
Python字符串格式化利器:f-strings入门指南
187 80
|
7月前
|
程序员 UED Python
Python入门:3.Python的输入和输出格式化
在 Python 编程中,输入与输出是程序与用户交互的核心部分。而输出格式化更是对程序表达能力的极大增强,可以让结果以清晰、美观且易读的方式呈现给用户。本文将深入探讨 Python 的输入与输出操作,特别是如何使用格式化方法来提升代码质量和可读性。
Python入门:3.Python的输入和输出格式化
|
1月前
|
监控 Linux 数据安全/隐私保护
Python实现Word转PDF全攻略:从入门到实战
在数字化办公中,Python实现Word转PDF自动化,可大幅提升处理效率,解决格式兼容问题。本文详解五种主流方案,包括跨平台的docx2pdf、Windows原生的pywin32、服务器部署首选的LibreOffice命令行、企业级的Aspose.Words,以及轻量级的python-docx+pdfkit组合。每种方案均提供核心代码与适用场景,并涵盖中文字体处理、表格优化、批量进度监控等实用技巧,助力高效办公自动化。
306 0
|
2月前
|
数据采集 分布式计算 大数据
不会Python,还敢说搞大数据?一文带你入门大数据编程的“硬核”真相
不会Python,还敢说搞大数据?一文带你入门大数据编程的“硬核”真相
85 1
|
3月前
|
NoSQL MongoDB 开发者
Python与MongoDB的亲密接触:从入门到实战的代码指南
本文详细介绍了Python与MongoDB结合使用的实战技巧,涵盖环境搭建、连接管理、CRUD操作、高级查询、索引优化、事务处理及性能调优等内容。通过15个代码片段,从基础到进阶逐步解析,帮助开发者掌握这对黄金组合的核心技能。内容包括文档结构设计、批量操作优化、聚合管道应用等实用场景,适合希望高效处理非结构化数据的开发者学习参考。
206 0
|
4月前
|
数据管理 开发者 Python
揭秘Python的__init__.py:从入门到精通的包管理艺术
__init__.py是Python包管理中的核心文件,既是包的身份标识,也是模块化设计的关键。本文从其历史演进、核心功能(如初始化、模块曝光控制和延迟加载)、高级应用场景(如兼容性适配、类型提示和插件架构)到最佳实践与常见陷阱,全面解析了__init__.py的作用与使用技巧。通过合理设计,开发者可构建优雅高效的包结构,助力Python代码质量提升。
401 10
|
4月前
|
数据采集 存储 NoSQL
分布式爬虫去重:Python + Redis实现高效URL去重
分布式爬虫去重:Python + Redis实现高效URL去重

推荐镜像

更多