34

Pythonアプリケーションでredisを使用して、カウンターやタイムスタンプリストなどの単純な値を格納していますが、カウンターを取得して数値と比較しようとすると、問題が発生しました。

私が行った場合:

import redis
...
myserver = redis.Redis("localhost")
myserver.set('counter', 5)

次に、次のようにその値を取得してみてください。

if myserver.get('counter') < 10:
     myserver.incr('counter')

次に、「5」<10を比較しているため、ifステートメントで型エラーが発生します。これは、整数値を格納し、文字列1(別の値と見なすことができる)を取得していることを意味します。

私の質問は:これはそのように機能するはずですか?つまり、非常に基本的なタイプです。オブジェクトを解析する必要があるかどうかはわかりますが、intですか?私は何か間違ったことをしているようです。

不足している構成はありますか?

redisが常に文字列ではなく正しいタイプを返すようにする方法はありますか?これは、リストと日時、さらには浮動小数点値でも同じであるためです。

これは、私が使用しているredis-pyクライアントの問題であり、redis自体ではない可能性がありますか?

4

8 に答える 8

19

技術的に言えば、あなたは自分でそれを処理する必要があります。

ただし、このリンク、特にパーサーと応答コールバックを参照するREADMEの部分を見てください。おそらく、これを使用できます。問題は、これがあなたにとってやり過ぎかどうかということです。

于 2012-10-25T02:30:19.960 に答える
16

@favorettiが言ったように、応答コールバックがそのトリックを行います。それはまったく複雑ではなく、1行だけですべてが処理されます。

In [2]: import redis
In [3]: r = redis.Redis()
In [10]: r.set_response_callback('HGET', float)
In [11]: r.hget('myhash', 'field0')
Out[11]: 4.6

の場合、単一の文字列ではなく文字列のリストを返すためhmget、もう少し包括的なコールバック関数を作成する必要があります。

In [12]: r.set_response_callback('HMGET', lambda l: [float(i) for i in l])

In [13]: r.hmget('myhash', 'field0')
Out[13]: [4.6]

についても同じですhgetall

于 2013-07-13T23:48:53.067 に答える
7

単純なデータ型の場合は活用set_response_callbackできますが、辞書、リスト、タプルなどを保存し、Pythonネイティブのデータ型を保持するための最も速くて簡単なルートについて疑問がある場合は、それらに含まれる場合と含まれない場合があります。 Pythonの組み込みpickleライブラリの使用をお勧めします。

# Imports and simplified client setup
>>> import pickle
>>> import redis
>>> client = redis.Redis()
# Store a dictionary
>>> to_store = {'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}
>>> client.set('TestKey', pickle.dumps(to_store))
True
# Retrieve the dictionary you just stored.
>>> retrieved = pickle.loads(client.get('TestKey'))
{'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}

pickle上記の例の定型文を減らし、Redisとの間でネイティブPythonデータ型を保存および取得するためのクリーンなインターフェイスを提供する単純なクライアントを次に示します。

"""Redis cache."""
import pickle
import redis

redis_host = redis.Redis()


class PythonNativeRedisClient(object):
    """A simple redis client for storing and retrieving native python datatypes."""

    def __init__(self, redis_host=redis_host):
        """Initialize client."""
        self.client = redis_host

    def set(self, key, value, **kwargs):
        """Store a value in Redis."""
        return self.client.set(key, pickle.dumps(value), **kwargs)

    def get(self, key):
        """Retrieve a value from Redis."""
        val = self.client.get(key)
        if val:
            return pickle.loads(val)
        return None

redis_client = PythonNativeRedisClient()

使用法:

>>> from some_module import redis_client
>>> to_store = {'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}
>>> redis_client.set('TestKey', to_store)
True
>>> retrieve = redis_client.get('TestKey')
{'a': 1, 'b': 'A string!', 'c': [1, True, False, 14.4]}
于 2018-12-12T21:16:42.753 に答える
6

Trueのようにdecode_responeを設定できます

redis.StrictRedis(host="localhost", port=6379, db=0, decode_responses=True)
于 2018-09-20T19:10:59.283 に答える
5

これが、redisがデータを保存する方法のようです。

redis 127.0.0.1:6379> set counter 5
OK
redis 127.0.0.1:6379> type counter
string
redis 127.0.0.1:6379> incr counter
(integer) 6
redis 127.0.0.1:6379> type counter
string

本当に必要な場合は、クライアントにモンキーパッチを適用してredis-pyデータ型を推測することができます。

于 2012-10-25T03:01:49.037 に答える
2

ニーズに応じて、Redisにデータを保存する3つの方法があります

  • すべてのデータが保存され、バイトとして読み戻されます。
  • これは、Redisで使用されているネイティブウェイメソッドです。
  • redis-cliデータの検査と操作に使用できます
  • ただし、データが効率的に保存されない場合があります。たとえば12345、2バイトのunsigned shortで表すことができる場合でも、少なくとも5バイトを使用して文字列として格納されます。
  • Redisが提供するさまざまなデータ構造の使用に制限することができます。
  • Redis内に保存されているデータは、Pythonやプログラミング言語のさまざまなバージョン間で移植可能です。

ピクルス

  • pickleすべてのPythonデータは、Redisに保存される前に、ライブラリを使用してバイナリデータに変換されます。
  • pickleデータを使用する前に、ライブラリを使用してデータをPythonデータ型に変換し直す必要があります。
  • Redisでは提供されていない複雑で動的なデータ構造をモデル化できます。
  • データがPythonデータ型に変換されたら、強力なPythonを使用してデータを操作できます。
  • pickleメタデータや参照を出力に含めるため、Redis内でより多くのメモリを使用します。
  • redis-cliなどのデータを操作するために使用することはできませんINCR
  • Redis内に保存されているデータは、Pythonやプログラミング言語のさまざまなバージョン間で移植できません。

構造体

  • structすべてのPythonデータは、Redisに保存される前に、ライブラリを使用してバイナリデータに変換されます。
  • structデータを使用する前に、ライブラリを使用してデータをPythonデータ型に変換し直す必要があります。
  • Redisでは提供されていない複雑で静的なデータ構造をモデル化できます。
  • データがPythonデータ型に変換されたら、強力なPythonを使用してデータを操作できます。
  • これらの3つの方法の中で最も少ないメモリを使用します
  • redis-cliなどのデータを操作するために使用することはできませんINCR
  • Redis内に保存されているデータは、Pythonやプログラミング言語のさまざまなバージョン間で移植可能です。
from redis import Redis
import sys
import pickle
import struct

redis = Redis()

# Data
d = [1234, 3.1415, b'Good', True]
k = ['int', 'float', 'byte', 'bool']

## Using String
print(f'String\n{"_"*50}')
# Need to convert True to string or int or float
d2 = [1234, 3.1415, b'Good', int(True)]
redis.hset('k0', mapping=dict(zip(k,d2)))
print(redis.hmget('k0', *k))
print()


## Using Pickle
print(f'Pickle\n{"_"*50}')
packed = pickle.dumps(d)
print(f'Pickled data occupies {sys.getsizeof(packed)} bytes')
print(packed)
redis.set('k1', packed)
print(f'{pickle.loads(redis.get("k1"))}')
print()


## Using Struct
print(f'Struct\n{"_"*50}')
s = struct.Struct('H f 10s ?')
print(f'The structure occupies {s.size} bytes.')
packed = s.pack(*d)
print(f'{packed}')
redis.set('k2', s.pack(*d))
print(f'{s.unpack(redis.get("k2"))}')

期待される出力:

String
__________________________________________________
[b'1234', b'3.1415', b'Good', b'1']

Pickle
__________________________________________________
Pickled data occupies 69 bytes
b'\x80\x04\x95\x19\x00\x00\x00\x00\x00\x00\x00]\x94(M\xd2\x04G@\t!\xca\xc0\x83\x12oC\x04Good\x94\x88e.'
[1234, 3.1415, b'Good', True]

Struct
__________________________________________________
The structure occupies 19 bytes.
b'\xd2\x04\x00\x00V\x0eI@Good\x00\x00\x00\x00\x00\x00\x01'
(1234, 3.1414999961853027, b'Good\x00\x00\x00\x00\x00\x00', True)
于 2020-08-09T17:35:33.277 に答える
1

これが私のテストです。2つのredis接続:1つはint型を返し、もう1つはfloatを返します

import redis

age_field = redis.Redis()
age_field.set_response_callback('HGET', int)
age_field.hget('foo', 'age')
# OUT: 40
a =age_field.hget('foo', 'age')
type(a)
# OUT: <type 'int'>

gpa_field = redis.Redis()
gpa_field.set_response_callback('HGET', float)
gpa_field.hget('foo', 'gpa')
# OUT: 2.5
b = gpa_field.hget('foo', 'gpa')
type(b)
# OUT: <type 'float'>
于 2013-12-06T22:01:47.193 に答える
0

1つの解決策は、の代わりに、を使用しjson.loads()て返すintfloat、正しい型として使用することですstr

import json
import redis

redis = redis.from_url("redis://************")

def get(key, decode=True):
    """set decode to False when value stored as a string"""
    value = redis.get(key)
    if not decode:
        return value
    if value is not None:
        try:
            return json.loads(value)
        except json.decoder.JSONDecodeError:
            # not containing a JSON document
            return value

redis.set("foo", 2)
redis.set("bar", 2.75)

get("foo")
# 2
get("bar")
# 2.75
于 2021-03-06T17:37:57.397 に答える