Python标准库系列之Redis模块

【Python】redis Redis (Remote Dictionary Server) 是一个开源的,使用C语言编写,遵守BSD协议的,支持网络、可基于内存亦可持久化的日志型、键值对存储系统,可以用作数据库、缓存和消息中间件。但要真正理解Redis,我们不能仅仅停留在其定义上,需要深入其设计哲学。Redis由Salvatore Sanfilippo(网名antirez)在2009年发明,最初是为了提升他公司产品的性能。他发现传统数据库在某些场景下无法满足高并发和低延迟的需求,于是决定自己开发一个更适合这些场景的内存数据库。Red 阅读详情

安装Redis

安装

模块GitHub地址:https://github.com/WoLpH/redis-py

[root@anshengme ~]# yum -y install redis

配置绑定的IP

在学习过程中有什么不懂得可以加我的
python学习交流扣扣qun,784758214
群里有不错的学习视频教程、开发工具与电子书籍。
与你分享python企业当下人才需求及怎么从零基础学习好python,和学习什么内容
[root@anshengme ~]# vim /etc/redis.conf 
bind 0.0.0.0

启动并设置开机自启动

[root@anshengme ~]# systemctl start redis
[root@anshengme ~]# systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.

检查

查看端口

[root@anshengme ~]# netstat -tlnp | grep "redis"
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      1439/redis-server 0 

数据写入测试

[root@anshengme ~]# /usr/bin/redis-cli 
127.0.0.1:6379> set url https://blog.ansheng.me
OK
127.0.0.1:6379> get url
"https://blog.ansheng.me"
127.0.0.1:6379> exit

安装redis-py

安装redis-py

pip3 install redis

或源码安装

python setup.py install

检查安装是否成功

# 导入模块没报错则安装成功
>>> import redis

入门及使用

# 导入模块
>>> import redis
# 连接到Redis服务器
>>> conn = redis.Redis(host='192.168.56.100', port=6379)
# 写入一条数据
>>> conn.set('name','ansheng')
True
# 获取一条数据
>>> conn.get('name')
b'ansheng'
>>> conn.get('url')
b'https://blog.ansheng.me'

使用连接池连接到Redis

Behind the scenes, redis-py uses a connection pool to manage connections to a Redis server. By default, each Redis instance you create will in turn create its own connection pool. You can override this behavior and use an existing connection pool by passing an already created connection pool instance to the connection_pool argument of the Redis class. You may choose to do this in order to implement client side sharding or have finer grain control of how connections are managed.

>>> pool = redis.ConnectionPool(host='192.168.56.100', port=6379)
>>> conn = redis.Redis(connection_pool=pool)
>>> conn.set('hello','world')
True
>>> conn.get('hello')
b'world'

使用套接字连接

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

API

redis-py提供的API用来操作redis

String API

set(name, value, ex=None, px=None, nx=False, xx=False)

参数描述
ex过期时间(秒)
px过期时间(毫秒)
nx如果设置为True,则只有name不存在时,当前set操作才执行
xx如果设置为True,则只有name存在时,岗前set操作才执行
>>> conn.set('k1', 'v1', ex=10, nx=True)
True
>>> conn.get('k1')
b'v1'
>>> conn.get('k1')

setex(name, value, time)

设置过期时间/秒

>>> conn.setex('k','v',1)
True
>>> conn.get('k')

psetex(name, time_ms, value)

设置过期时间/毫秒

>>> conn.psetex('k',10,'v')
True
>>> conn.get('k')

setnx(name, value)

设置值,只有key不存在时,执行设置操作

>>> conn.get('k1')
>>> conn.setnx('k1','v1')
True
>>> conn.get('k1')
b'v1'
>>> conn.setnx('k2','v2')
False

**mset(*args, kwargs)

同时设置多个key/value

>>> conn.mset(k1='v1', k2='v2')
True
>>> conn.mset({'k1':'v1', 'k1':'v1'})
True

get(name)

获取单个值

>>> conn.get('k1')
b'v1'

*mget(keys, args)

获取多个值

>>> conn.mget('k1','k2')
[b'v1', b'v2']
# 传入列表
>>> conn.mget(['name','url'])
[b'ansheng', b'https://blog.ansheng.me']

getset(name, value)

设置新值并获取原来的值

>>> conn.set('hello', 'world')
True
>>> result = conn.getset('hello', 'Linux')
>>> result
b'world'
>>> conn.get('hello')
b'Linux'

getrange(key, start, end)

通过索引的方式来获取value的值

>>> conn.set('key','value')
True
>>> conn.getrange('key', 1, 4)
b'alue'

setrange(name, offset, value)

根据索引修改value

>>> conn.set('n','123456789')
True
>>> conn.setrange('n', 0, 'a')
9
>>> conn.get('n')
b'a23456789'

setbit(name, offset, value)

getbit(name, offset)

获取value对应某一个索引位置对应的值0/1

>>> conn.getbit('k',1)
1

bitcount(key, start=None, end=None)

获取key对应二进制中表示1的个数

*bitop(operation, dest, keys)

将多个值进行值运算,得出的结果保存到一个新值当中

>>> conn.mset(n1='abc',n2='cde',n3='adc')
True
>>> conn.bitop('AND','now_key','n1','n2','n3')
3
>>> conn.get('now_key')
b'a`a'
>>> conn.mget('n1','n2','n3')
[b'abc', b'cde', b'adc']

operation支持AND(并)、OR(或)、NOT(非)、XOR(异或)

strlen(name)

获取value的长度

>>> conn.set('name','安生')
True
>>> conn.strlen('name')
6

incr(name, amount=1)

对name的value进行自增,如果name不存在则创建,否则自增

>>> conn.get('number')
>>> conn.incr('number')
1
>>> conn.get('number')
b'1'
>>> conn.incr('number')
2
>>> conn.incr('number', 10)
12

incrbyfloat(name, amount=1.0)

同上,支持浮点数自增

>>> conn.incrbyfloat('number', 1.5)
13.5
>>> conn.incrbyfloat('number', 1.1)
14.6

decr(name, amount=1)

自减,同自增一样,如果进行自减的value不是整数就报错

>>> conn.set('n', 10)
True
>>> conn.decr('n')
9
>>> conn.decr('n', 9)
0

append(key, value)

在value后面追加内容

>>> conn.set('blog','https://blog.ansheng.me')
True
>>> conn.append('blog','/')
26
>>> conn.get('blog')
b'https://blog.ansheng.me/'

Hash API

hset(name, key, value)

设置name的键值对,有则修改,没有则创建

>>> conn.hset('dic','k1','v1')
1
>>> conn.hget('dic','k1')
b'v1'

hmset(name, mapping)

同时设置多个name的key/value

>>> conn.hmset('dic', {'k1': 'v1', 'k2': 'v2'})
True
>>> conn.hget('dic','k2')
b'v2'

hget(name, key)

获取name中key的值

>>> conn.hget('dic','k2')
b'v2'

*hmget(name, keys, args)

同时获取多个

>>> conn.hmget('dic',['k1', 'k2'])
[b'v1', b'v2']
>>> conn.hmget('dic','k1', 'k2')
[b'v1', b'v2']

hgetall(name)

获取name对应的所有key/value

>>> conn.hgetall('dic')
{b'k1': b'v1', b'k2': b'v2'}

hlen(name)

获取name对应键值对的个数

>>> conn.hlen('dic')
2

hkeys(name)

获取name中所有的key

>>> conn.hkeys('dic')
[b'k1', b'k2']

hvals(name)

获取name中所有的value

>>> conn.hvals('dic')
[b'v1', b'v2']

hexists(name, key)

检查当前name中是否有传入的key

>>> conn.hexists('dic','k1')
True
>>> conn.hexists('dic','kk')
False

*hdel(self, name, keys)

删除name中对应的key

>>> conn.hdel('dic','k1')
1
>>> conn.hget('dic','k1')

hincrby(name, key, amount=1)

name中key对应的value进行自增,如果不存在则创建

>>> conn.hincrby('dic','number')
1
>>> conn.hincrby('dic','number',10)
11

hincrbyfloat(name, key, amount=1.0)

value自增,支持浮点数,同上

>>> conn.hincrbyfloat('dic','float')
1.0
>>> conn.hincrbyfloat('dic','float',0.3)
1.3

hscan(name, cursor=0, match=None, count=None)

增量式迭代获取,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆

参数描述
nameredis的name
cursor游标(基于游标分批取获取数据)
match匹配指定key,默认None 表示所有的key
count每次分片最少获取个数,默认None表示采用Redis的默认分片个数

hscan_iter(name, match=None, count=None)

利用yield封装hscan创建生成器,实现分批去redis中获取数据

参数描述
match匹配指定key,默认None 表示所有的key
count每次分片最少获取个数,默认None表示采用Redis的默认分片个数

如:

for item in r.hscan_iter('xx'):
    print item

expire(name, time)

设置过期时间

>>> conn.hset('info','BlogUrl','https://blog.ansheng.me')
1
>>> conn.expire('info', 10)
True
>>> conn.hget('info','BlogUrl')
b'https://blog.ansheng.me'
>>> conn.hget('info','BlogUrl')

ListAPI

*lpush(name, values)

在最左边添加值

>>> conn.lpush('li', 11,22,33)
3
>>> conn.lindex('li', 0)
b'33'

*rpush(name, values)

在最右边添加值

>>> conn.rpush('lli', 11,22,33)
3
>>> conn.lindex('lli', 0)
b'11'

lpushx(name, value)

只有name已经存在时,值添加到列表的最左边

>>> conn.lpushx('li', 'aa')
4
>>> conn.lindex('li', 0)
b'aa'

rpushx(name, value)

只有name已经存在时,值添加到列表的最右边

>>> conn.rpushx('li', 'bb')
5
>>> conn.lindex('li', 0)
b'aa'
>>> conn.lindex('li', 4)
b'bb'

llen(name)

获取name元素的个数

>>> conn.llen('li')
5

linsert(name, where, refvalue, value)

在name的某一个值前面或者后面插入一个新值

>>> conn.linsert('li','AFTER','11','cc')
6
>>> conn.lindex('li', 3)
b'11'
>>> conn.lindex('li', 4)
b'cc'

lset(name, index, value)

对name中index索引位置的值进行重新赋值

>>> conn.lindex('li', 4)
b'cc'
>>> conn.lset('li', 4, 'hello')
True
>>> conn.lindex('li', 4)
b'hello'

lrem(name, value, num=0)

删除指定value后面或者前面的值

  1. num=2,从前到后,删除2个;
  2. num=-2,从后向前,删除2个
>>> conn.llen('li')
6
>>> conn.lrem('li', 'hello')
1
>>> conn.llen('li')
5
>>> conn.lrem('li', '22', num=2)
2
>>> conn.llen('li')
3

lpop(name)

删除name中左侧第一个元素

>>> conn.lindex('li', 0)
b'11'
>>> conn.lpop('li')
b'11'

rpop(name)

删除name中右侧第一个元素

>>> conn.rpop('li')
b'33'

lindex(name, index)

获取name中对应索引的值

>>> conn.lindex('li', 0)
b'aa'

lrange(name, start, end)

使用切片获取数据

>>> conn.llen('li')
8
>>> conn.lrange('li',0,5)
[b'3', b'23', b'34', b'235', b'2', b'1']

ltrim(name, start, end)

在name对应的列表中移除没有在start-end索引之间的值

>>> conn.ltrim('li',0,5)
True
>>> conn.llen('li')
6

rpoplpush(src, dst)

从src列表中取出最右边的元素,同时将其添加至dst列表的最左边

>>> conn.lpush('li1', 1,2,3)
3
>>> conn.lpush('li2', 'a','b','c')
3
>>> conn.rpoplpush('li1','li2')
b'1'

blpop(keys, timeout=0)
brpop(keys, timeout=0)

brpoplpush(src, dst, timeout=0)

从src列表的右侧移除一个元素并将其添加到dst列表的左侧

>>> conn.lpush('ll', 'a','b','c')
3
>>> conn.lpush('aa', 'a','b','c')
3
>>> conn.brpoplpush('ll','aa')
b'a'

timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞

自定义增量迭代

由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要:

  1. 获取name对应的所有列表
  2. 循环列表

但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能:

def list_iter(name):
    """
    自定义redis列表增量迭代
    :param name: redis中的name,即:迭代name对应的列表
    :return: yield 返回 列表元素
    """
    list_count = r.llen(name)
    for index in xrange(list_count):
        yield r.lindex(name, index)

使用

for item in list_iter('pp'):
    print item

SET API

*sadd(name, values)

为name添加值,如果存在则不添加

>>> conn.sadd('s1', 1)
1
>>> conn.sadd('s1', 1)
0

scard(name)

返回name的元素数量

>>> conn.scard('s1')
1

*sdiff(keys, args)

在keys集合中不在其他集合中的数据

>>> conn.sdiff('s1','s2')
{b'c', b'v', b'a'}

*sdiffstore(dest, keys, args)

在keys集合中不在其他集合中的数据保存到dest集合中

>>> conn.sdiffstore('news','s1','s2')
3
>>> conn.scard('news')
3

*sinter(keys, args)

获取keys集合中与其他集合中的并集

>>> conn.sinter('s1','s2')
{b'2', b'3', b'1'}

*sinterstore(dest, keys, args)

获取keys集合中与其他集合中的并集数据并保存到dest集合中

>>> conn.sinterstore('news1','s1','s2')
3

sismember(name, value)

获取value是否是name集合中的成员

>>> conn.sismember('news1','1')
True
>>> conn.sismember('news1','aa1')
False

smembers(name)

获取name集合中所有的成员

>>> conn.smembers('news1')
{b'2', b'3', b'1'}

smove(src, dst, value)

将src中的value移动到dst中

>>> conn.smembers('s1')
{b'c', b'2', b'v', b'1', b'3', b'a'}
>>> conn.smembers('s2')
{b'2', b'3', b'1'}
>>> conn.smove('s1','s2','v')
True
>>> conn.smembers('s1')
{b'c', b'2', b'a', b'3', b'1'}
>>> conn.smembers('s2')
{b'2', b'v', b'3', b'1'}

spop(name)

删除并返回name中的随机成员

>>> conn.smembers('s2')
{b'2', b'v', b'3', b'1'}
>>> conn.spop('s2')
b'3'
>>> conn.smembers('s2')
{b'2', b'v', b'1'}
>>> conn.spop('s2')
b'2'
>>> conn.smembers('s2')
{b'v', b'1'}
>>> conn.spop('s2')
b'1'
>>> conn.smembers('s2')
{b'v'}

srandmember(name, number=None)

随机获取name集合中的number个成员,默认number=1

>>> conn.smembers('s1')
{b'c', b'2', b'a', b'3', b'1'}
>>> conn.srandmember('s1')
b'1'
>>> conn.srandmember('s1')
b'a'
>>> conn.srandmember('s1',number=2)
[b'3', b'a']
>>> conn.srandmember('s1',number=2)
[b'1', b'2']

*srem(name, values)

删除name集合中的values数据

>>> conn.smembers('s1')
{b'c', b'2', b'a', b'3', b'1'}
>>> conn.srem('s1','1','2')
2
>>> conn.smembers('s1')
{b'c', b'a', b'3'}

*sunion(keys, args)

获取keys集合与其他集合的并集

>>> conn.sadd('a1',1,2,3)
3
>>> conn.sadd('a2',1,2,3,4,5,6,7)
7
>>> conn.sunion('a2','a1')
{b'2', b'7', b'1', b'3', b'6', b'5', b'4'}

*sunionstore(dest, keys, args)

获取keys集合与其他集合的并集并保存到dest中

>>> conn.sunionstore('a3', 'a2','a1')
7
>>> conn.smembers('a3')
{b'2', b'7', b'1', b'3', b'6', b'5', b'4'}

Ordered set API

**zadd(name, *args, kwargs)

>>> conn.zadd('h1','n1',11,'n2',22)
2
>>> conn.zadd('h2',n1=11,n2=22)
2

zcard(name)

返回有序集合name元素的数量

>>> conn.zcard('h1')
2

zcount(name, min, max)

返回在name中值在min与max之间的值个数

>>> conn.zcount('h1',10,30)
2

zincrby(name, value, amount=1)

name中让value的值加上amount

>>> conn.zincrby('h1','n1',10)
21.0

zinterstore(dest, keys, aggregate=None)
zlexcount(name, min, max)

zrange(name, start, end, desc=False, withscores=False, score_cast_func=float)

参数描述
nameredis的name
start有序集合索引起始位置(非分数)
end有序集合索引结束位置(非分数)
desc排序规则,默认按照分数从小到大排序
withscores是否获取元素的分数,默认只获取元素的值
score_cast_func对分数进行数据转换的函数
>>> conn.zrange('h1', 1, 2, desc=True, withscores=True, score_cast_func=float)
[(b'n1', 21.0)]
>>> conn.zrange('h1', 1, 2, desc=False, withscores=True, score_cast_func=float)
[(b'n2', 22.0)]
# 从大到小排序
zrevrange(name, start, end, withscores=False, score_cast_func=float) 
# 按照分数范围获取name对应的有序集合的元素
zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)
# 从大到小排序
zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)

zrangebylex(name, min, max, start=None, num=None)

当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员

对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大

参数描述
nameredis的name
min左区间(值) + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间
min右区间(值)
start对结果进行分片处理,索引位置
num对结果进行分片处理,索引后面的num个元素

如:

ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga
# r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca']

更多:

# 从大到小排序
zrevrangebylex(name, max, min, start=None, num=None)

zrevrangebylex(name, max, min, start=None, num=None)

zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)**

zrank(name, value)

返回基于0的值,指示在排序集名称的值排名

>>> conn.zrank('h1','n1')
0
>>> conn.zrank('h1','n2')
1

zrevrank(name, value),从大到小排序

*zrem(name, values)

删除name中对应的values

>>> conn.zrem('h1','n2')
1
>>> conn.zrem('h2',['n1','n2'])
2

zremrangebyrank(name, min, max)

根据排行范围进行删除

>>> conn.zremrangebyrank('h1',1,2)
1

zremrangebyscore(name, min, max)

根据分数范围进行删除

>>> conn.zremrangebyscore('h1',10,20)
2

zscore(name, value)

返回指定value的值是多少

>>> conn.zscore('h1','n1')
11.0

zunionstore(dest, keys, aggregate=None)

Global API

*delete(names)

在redis中删除names

>>> conn.delete('ooo')
1

exists(name)

检测name是否存在

>>> conn.exists('iii')
False
>>> conn.exists('h1')
True

keys(pattern=’*’)

# 匹配数据库中所有 key 
>>> conn.keys(pattern='*')
[b'h2', b'kasd1', b'n2', b'url', b'name', b'n', b'li1', b'n1', b's1', b'now_key', b'l', b's2', b'number', b'numbers', b'a2', b'dic', b'a1', b'news', b'news1', b'aa', b'key', b'lli', b'll', b'k', b'li', b'k2', b'h1', b'li2', b'ccc', b'k1', b'blog', b'kaasdsd1', b'a3', b'l1', b'l2', b'n3', b'a']
# 匹配hello,hallo和hxllo等
conn.keys(pattern='h?llo')
# 匹配hllo和heeeeello 等
conn.keys(pattern='h*llo')
# 匹配hello和hallo,但不匹配 hillo
conn.keys(pattern='h[ae]llo')

rename(src, dst)

把src重命名成dst

>>> conn.set('k','v')
True
>>> conn.get('k')
b'v'
>>> conn.rename('k', 'kk')
True
>>> conn.get('k')
>>> conn.get('kk')
b'v'

move(name, db)

将redis的某个值移动到指定的db下

randomkey()

随机获取一个redis的name,不进行删除

>>> conn.randomkey()
b'll'
>>> conn.randomkey()
b'news1'

type(name)

查看name的类型

>>> conn.type('kk')
b'string'

管道

redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作(MySQL中的事务)。

>>> import redis
>>> pool = redis.ConnectionPool(host='192.168.56.100', port=6379)
>>> r = redis.Redis(connection_pool=pool)
# 创建一个通道支持事务
>>> pipe = r.pipeline(transaction=True)
#
>>> r.set('hello', 'world')
True
>>> r.set('blog', 'ansheng.me')
True
# 如果在设置上面两个值的过程中出错了,那么这次提交就不会执行
>>> pipe.execute()
[]

发布订阅

# monitor.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import redis

class RedisHelper:
    def __init__(self):
        self.__conn = redis.Redis(host='192.168.56.100')
        self.chan_sub = 'fm104.5'
        self.chan_pub = 'fm104.5'

    def public(self, msg):
        self.__conn.publish(self.chan_pub, msg)
        return True

    def subscribe(self):
        pub = self.__conn.pubsub()
        pub.subscribe(self.chan_sub)
        pub.parse_response()
        return pub

# subscriber.py 订阅者
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from monitor import RedisHelper

obj = RedisHelper()
redis_sub = obj.subscribe()

while True:
    msg = redis_sub.parse_response()
    print(msg)

# announcer.py 发布者
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from monitor import RedisHelper

obj = RedisHelper()
obj.public('hello')

实例

让redis缓存tornado页面

# _*_coding:utf-8 _*_

import tornado.ioloop
import tornado.web
import time
import redis

poll = redis.ConnectionPool(host='192.168.56.100', port=6379)
conn = redis.Redis(connection_pool=poll)

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        CurrentTim = conn.get('CurrentTim')
        if CurrentTim:
            self.write(CurrentTim)
        else:
            CurrentTim = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
            conn.set('CurrentTim', CurrentTim, ex=5)
            self.write(CurrentTim)

settings = {
    "tempalte_path": "template",
}

application = tornado.web.Application([
    (r'/', MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(9999)
    tornado.ioloop.IOLoop.instance().start()

基于Redis的Session存储

app.py

# _*_coding:utf-8 _*_

import tornado.ioloop
import tornado.web
import RedisToSession

class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = RedisToSession.Session(self)

class MainHandler(BaseHandler):
    def get(self):
        Info = self.session.GetAll()

        self.render("template/index.html", Data=Info)

    def post(self, *args, **kwargs):
        # 获取传过来的值
        Key = self.get_argument('key')
        Val = self.get_argument('val')
        action = self.get_argument('action')
        if action == 'set':
            # 设置值
            self.session[Key] = Val
        elif action == 'del':
            del self.session[Key]

        # 获取所有信息
        Info = self.session.GetAll()
        # 返回给前端渲染
        self.render("template/index.html", Data=Info)

settings = {
    "tempalte_path": "template",
    "cookie_secret": "508CE6152CB93994628D3E99934B83CC",
}

application = tornado.web.Application([
    (r'/', MainHandler),
], **settings)

if __name__ == "__main__":
    application.listen(9999)
    tornado.ioloop.IOLoop.instance().start()

template\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>

<form action="/" method="post">
    set/del:<input type="text" name="action" value="set"/>
    Key: <input type="text" name="key"/>
    Val: <input type="text" name="val"/>
    <input type="submit" value="设置"/>
</form>

{{ Data }}

</body>
</html>

如果你依然在编程的世界里迷茫,可以加入我们的Python学习扣qun:784758214,看看前辈们是如何学习的!交流经验!自己是一名高级python开发工程师,从基础的python脚本到web开发、爬虫、django、数据挖掘等,零基础到项目实战的资料都有整理。送给每一位python的小伙伴!分享一些学习的方法和需要注意的小细节,点击加入我们的 python学习者聚集地

RedisToSession.py

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

import redis
import hashlib
import uuid
import json

# 连接memcached
pool = redis.ConnectionPool(host='192.168.56.100', port=6379)
conn = redis.Redis(connection_pool=pool)

class Session:
    CookieID = 'uc'
    ExpiresTime = 60 * 20

    def __init__(self, handler):
        """
        用于创建用户session在redis中的字典
        :param handler: 请求头
        """
        self.handler = handler
        # 从客户端获取随机字符串
        SessionID = self.handler.get_secure_cookie(Session.CookieID, None)
        # 客户端存在并且在服务端也存在
        if SessionID and conn.exists(SessionID):
            self.SessionID = SessionID
        else:
            # 获取随机字符串
            self.SessionID = self.SessionKey()
            # 把随机字符串写入memcached,时间是20分钟
            conn.hset(self.SessionID, None, None)

        # 每次访问超时时间就加20分钟
        conn.expire(self.SessionID, Session.ExpiresTime)

        # 设置Cookie
        self.handler.set_secure_cookie('uc', self.SessionID)

    def SessionKey(self):
        """
        :return: 生成随机字符串
        """
        UUID = str(uuid.uuid1()).replace('-', '')
        MD5 = hashlib.md5()
        MD5.update(bytes(UUID, encoding='utf-8'))
        SessionKey = MD5.hexdigest()
        return SessionKey

    def __setitem__(self, key, value):
        """
        :param key: session信息中的key
        :param value: 对应的Value
        """
        conn.hset(self.SessionID, key, value)

    def __getitem__(self, item):
        """
        :param item: Session信息中对应的Key
        :return: 获取的Session信息
        """
        # 获取对应的数据
        ResultData = conn.hget(self.SessionID, item)
        return ResultData

    def __delitem__(self, key):
        """
        :param key: 要删除的Key
        """
        conn.hdel(self.SessionID, key)

    def GetAll(self):
        # 获取Session中所有的信息,仅用于测试
        SessionData = conn.hgetall(self.SessionID)
        return SessionData
【Python】 Shelve 模块 数据持久化的方法多种多样,从简单的文本文件(CSV, JSON, XML)到复杂的关系型数据库(MySQL, PostgreSQL, SQLite)和非关系型数据库(Redis, MongoDB),每种方案都有其特定的适用场景和优劣。然而,对于Python开发者而言,有时我们需要一种介于“普通文件存储”和“完整数据库系统”之间的轻量级解决方案——它既能提供比纯文本文件更便捷的结构化数据访问方式,又无需部署和维护一个复杂的数据库服务器。正是在这样的背景下,Python标准库中的模块应运而生。模块提供了一个简单 阅读详情

相关推荐

《Python全栈系列教程》专栏介绍及文章汇总

《Python全栈系列教程》专栏介绍及文章汇总

孤寒者的博客 71万+

22Python标准库系列之Redis模块

Python标准库系列之Redis模块What is redis?Redis is an open source (BSD licensed), in-memory data structure store, used as database, cache and message broker. It supports data structures such as stri...

weixin_33970449的博客 356

现控报告-- 分析倒立摆系统稳定性、能控性及能观性分析,设计PID控制方案(附matlab)

建立直线一级倒立摆系统的动力学模型,推导该系统的运动方程,求出直线一级倒立摆系统传递函数模型及空间状态方程模型。接着描述了PID控制系统设计原理及PID控制器各校正环节的作用,简要叙述了参数的整定方法。设计了直线一级倒立摆摆杆摆角及小车位置常规单回路控制器,通过Simulink仿真知道常规单回路控制器能控制摆杆摆角,不能控制小车位置。于是设计出了直线一级倒立摆双闭环控制器及基于倒立摆系统的状态空间方程控制器,利用软件进行仿真,仿真结果表明,常规双闭环控制方案和基于状态空间方程加控制方案均能对摆杆摆角及小车位

mengshenglo的博客 4万+

python往redis导数_Python操作Redis

昨天,我们讨论了python如何连接redis。今天我们要学习如何用python操作redis的数据。这里,再补充一下。redis是key-value形式的数据库。可以存储多种格式的数据。今天,我们就是尝试下,这些常用的api。1.设置数据:r = redis.Redis(host='127.0.0.1', port=6379)#若是key存在,就修改,不存在,就添加r.set('zcx', '1...

weixin_39531635的博客 281

数学建模 种群竞争模型 学习笔记

模型背景 应用场景 种群竞争模型 例如 s1=0.5,则表示对于供养甲的资源来讲,单位数量的乙的消耗为单位数量的甲的0.5倍,即表示乙对于该资源的占有能力是甲的0.5倍(即竞争力弱) 仿真结果及分析 (1)设置自然增长率 r1=r2=1 (2)改变自然增长率 r1=r2=0.3 (3)修改甲和乙的最大容量 n1=10000, n2=100 (4)修改甲和乙的初始数量 x1=10, x...

Test_tju的博客 2029

基于PDF文档结构的数字隐写

PDF隐写

xiongshivigor的博客 1426

【Python】Redis数据库

Redis基础学习

Cerulea_n的博客 2211

双轮差动机器人SLAM实战:轮速里程计从建模到精度验证(附Matlab代码)

本文详细介绍了双轮差动机器人SLAM系统中轮速里程计的实现全流程,包括核心原理、建模方法、Matlab代码实现及精度验证。通过轮速仪数据建模和连续积分算法,提升定位精度,并附有完整的误差分析和工程优化技巧,为开发者提供实用参考。

weixin_29050271的博客 224

Python3 操作 Redis

一、简单介绍 redis是一个key-value存储系统,和Memcached类似。它支持存储的value类型相对更多,包括string(字符串)、list(链表、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各...

Richardlygo的博客 1416

福彩快乐8智能选号系统研究

本文介绍了一款福彩快乐8智能选号系统的开发过程。系统首先通过数据采集获取历史开奖数据,作为分析的基础。随后,对采集的数据进行深入分析,以识别可能的模式和趋势。基于这些分析,系统能够智能预测未来的开奖号码,如2025129期的预测。最后,通过模拟兑奖功能,用户可以直观地看到预测结果的实际效果。文章鼓励感兴趣的读者点赞并领取源代码,以便自行探索和使用该系统。

gumuzi1210的博客 2222

融合双主干网络提升YOLOv8性能一种基于SOTA思想的目标检测改进

YOLOv8采用了单一的主干网络进行特征提取,通常是基于CSPDarknet作为骨干网络,在目标检测过程中通过不同的卷积层提取不同尺度的信息。虽然这种设计在大多数应用场景下表现出色,但在面对复杂背景、细节丰富的物体或小物体检测时,YOLOv8有时难以保持良好的精度。在本文中,我们提出了一种基于双主干网络的YOLOv8改进方案,通过结合先进的SOTA思想,全面提升了YOLOv8在目标检测任务中的表现。双主干网络架构。

博客 1154

Python标准库系列之Redis模块--Redis常用命令

Python标准库系列之Redis模块–Redis常用命令 参考网址:[link]https://www.cnblogs.com/qtxdy/p/7723411.html 官方文档:[link]https://redis-py.readthedocs.io/en/latest/#indices-and-tables 连接操作命令 quit:关闭连接(connection) auth:简单密...

weixin_44726980的博客 621

【人工智能】RAG如何根据实际需求选择和进行文档解析(如 PDF、Word、TXT、网页等)?

文档解析的核心在于根据解析目标、文档类型和处理量选择合适工具。PDF、Word、TXT和网页各有特性:PDF需区分可编辑与扫描版,Word需处理结构化内容,TXT简单但需注意编码,网页需应对动态内容。解析场景包括提取纯文本、结构化数据、保留格式和批量处理。非技术用户可借助工具如Adobe Acrobat、WPS和在线OCR,技术用户可通过编程实现自动化。通用流程为:明确目标、分析文档属性、选择工具并测试优化。核心是“工具适配需求”,无需追求万能方案。

奶爸的编程之路,也就一周冷个三天 509

Python - redis 模块 - 进阶之路 - Day07

redis介绍 1. Redis是一个开源(BSD许可),内存数据结构存储,用作数据库,缓存和消息代理。 2. 它支持数据结构,如 字符串,散列,列表,集合,带有范围查询的排序集,位图,超级日志和带有半径查询的地理空间索引。 3. Redis具有内置复制,Lua脚本,LRU驱逐,事务和不同级别的磁盘持久性,并通过Redis Sentinel提供高可用性和Redis Cluster自动分区。 redis定义 1. redis是一个key-value存储系统。和Memcached类似,它支持存储的va

lixiang5453的博客 1087

STM32实战开发(66):STM32图像处理开发教程

随着物联网、人工智能和嵌入式技术的不断发展,图像处理技术在嵌入式系统中的应用越来越广泛。图像处理不仅在视觉识别、安防监控、智能家居等领域中发挥着重要作用,也在工业自动化、医疗成像、无人驾驶等高科技领域中占据重要地位。而STM32凭借其强大的硬件性能和丰富的外设支持,成为了许多图像处理应用的理想平台。

2201_76125393的博客 1448

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

#####好######Python标准库系列之Redis模块

Python标准库系列之Redis模块 What is redis? Redis is an open source (BSD licensed), in-memory data structure store, used as database, cache and message broker. It supports data structures such as str

木东的博客 1026

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

python redis模块常用_python之redis模块

一、redis简介redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各...

weixin_39530269的博客 144

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Python标准库与扩展库全解析

Python标准库与扩展库概述 1. 标准库 Python标准库是语言自带的模块集合,涵盖基础开发需求,标准库无需额外安装,为开发者提供开箱即用的功能。 2. 扩展库 标准库奠定开发基础,扩展库则推动Python在专业领域的深度应用11。两者共同构建了Python高效、灵活的编程生态。

2401_87975790的博客 1894

Python标准库和第三方库

Python标准库和第三方库共同构成了Python的强大生态系统,为开发者提供了丰富的功能和工具。

Flask Web 899

Ubuntu上 Python MySQL 应用会话管理的 Redis 加速指南

然后,Python 脚本将用户的登录凭证缓存在 Redis 数据库中,以服务于其他未来的请求。在该文件中,您将创建一个代码,显示当前服务器的时间给经过身份验证的用户。在这一步中,您将设置一个中心模块,允许您从 Python 脚本连接并查询 MySQL 数据库。在本指南中,您将使用 Redis 数据库来加速 Ubuntu 22.04 服务器上的 Python/MySQL 应用程序的会话处理。在下一步中,您将构建一个与您的示例数据库通信的 Python 模块。在下一步中,您将测试应用程序。

qq_57526628的博客 1038

Python 学习 ---> 模块、pypi ( 模块库 )、添加模块路径

什么是 模块 在 Python 中,一个.py文件就是一个模块(Module)。模块的名字就是文件的名字。在模块内部,通过全局变量__name__可以获取模块名(即字符串) 模块作用 为了实现代码的复用,通常会把一些其他程序中重用的代码拿出来单独放在一个程序文件中,

freeking101的博客 3487

redispython源文件_Python hot-redis包_程序模块 - PyPI - Python中文网

用法热redis提供的每种类型都力求实现相同的方法签名和返回值作为其python内置和标准库副本。主要的区别是每种类型的__init__方法。每个热redis类型的__init__方法都将可选地接受initial和key关键字参数,它们是用于定义要存储在redis中的对象和应分别使用的键。如果没有钥匙如果生成密钥,则可以通过key属性:>>> from hot_redis imp...

weixin_39655689的博客 86

Redis与Python编程实践

1.背景介绍 1. 背景介绍 Redis(Remote Dictionary Server)是一个开源的高性能键值存储系统,由 Salvatore Sanfilippo 在2009年开发。Redis 支持数据的持久化,不仅仅支持简单的键值对存储,还提供列表、集合、有序集合等数据结构的存储。Redis 还通过提供多种数据结构的存储支持,为开发者提供了更多的可能性。 Python 是一种高级的、...

AI天才研究院 976

Python 的时间处理模块 datetime 详解

datetime模块是 Python 中用于处理日期和时间的标准库,它提供了日期和时间的获取、格式化、解析、运算等功能,是开发者进行时间处理的常用工具。

想看什么文章都可以私信给我,综合性博客。 1209

python模块

python模块 hashlib-md5 import hashlib m = hashlib.md5() #创建hash对象:md5:消息摘要算法,得出一个128位密友 print(m) #<md5 HASH object> m.update(b'itcast') #更新哈希对象以字符串参数 print(m.hexdigest())#反回十六进制数字字符串 # 运行结果...

xiao-啸 203

redis-py 在 Python 中连接与使用 Redis

Redis 是一个开源的高性能键值数据库,redis-py 则是官方推荐的 Python 客户端。本指南介绍如何安装 redis-py、连接到 Redis 服务器、执行常见读写操作,以及获取更多进阶使用资源。

hello.reader 891
上一篇: Python标准库系列之Paramiko模块
下一篇: Python标准库系列之Memcache模块
Python老王
博客等级 码龄7年 159粉丝 224原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值