if nx:
pieces.append('NX')
if xx:
pieces.append('XX')
return self.execute_command('SET', *pieces)
__setitem__ = set
从这里面还看不出什么 ,我们注意到这一方法重点是处理后面的默认参数再前面调用究竟有没有传递,其实可以忽略,这不是我们关注点。我们注意到这个方法最后是交给execute_command去处理的,因此我们找出 execute_command的源码:
def execute_command(self, *args, **options):
"Execute a command and return a parsed response"
pool = self.connection_pool
command_name = args[0]
connection = pool.get_connection(command_name, **options)
try:
connection.send_command(*args)
return self.parse_response(connection, command_name, **options)
except ConnectionError:
connection.disconnect()
connection.send_command(*args)
return self.parse_response(connection, command_name, **options)
finally:
pool.release(connection)
重点在try 里面 connection.send_command(*args)。还是没找到我们想要的,继续找到send_command 的源代码:
def send_command(self, *args):
"Pack and send a command to the Redis server"
self.send_packed_command(self.pack_command(*args))
不多说 继续找 pack_command 源代码(在 connection 模块):
def pack_command(self, *args):
"Pack a series of arguments into a value Redis command"
output = BytesIO()
output.write(SYM_STAR)
output.write(b(str(len(args))))
output.write(SYM_CRLF)
for enc_value in imap(self.encode, args):
output.write(SYM_DOLLAR)
output.write(b(str(len(enc_value))))
output.write(SYM_CRLF)
output.write(enc_value)
output.write(SYM_CRLF)
return output.getvalue()
感觉是不是迷糊了? 哈哈
其实 就是这里我们找对了!!!!!
好吧,看这段代码之前,我们首先了解一下 redis协议的基本知识。
See the following example:
*3
$3
SET
$5
mykey
$7
myvalue
This is how the above command looks as a quoted string, so that it is possible to see the exact value of every byte in the query, including newlines.
这里就是对args里面的参数作一定转换,同样我们找到self.encode源代码:
def encode(self, value):
"Return a bytestring representation of the value"
if isinstance(value, bytes):
return value
if isinstance(value, float):
value = repr(value)
if not isinstance(value, basestring):
value = str(value)
if isinstance(value, unicode):
value = value.encode(self.encoding, self.encoding_errors)
return value
注意到没有,if not isinstance(value, basestring):
value = str(value)
这里意思就是说,如果不是str类型,会把该值强制转换为str类型。原来这样,怪不得我们说set(None,'Test') 和set('None','Test') 是一回事,其实,不应该这样。
既然这样我们稍作修改:
if value == None:
value = value
else:
value = str(value)
这样修改就可以了吗?。。。当然不是啦!!。。。我们接下来看pack_command的代码,
for enc_value in imap(self.encode, args):
output.write(SYM_DOLLAR)
output.write(b(str(len(enc_value))))
output.write(SYM_CRLF)
output.write(enc_value)
output.write(SYM_CRLF)
return output.getvalue()
我们上面的value不再强制转换为str类型后,那么output.write(b(str(len(enc_value)))) 就有可能报异常,当enc_value 为None时len 函数报异常,因此我们要避免这种异常,可以这样改:
if enc_value == None:
output.write(b(str(len(enc_value))))
else:
output.write(b(str(0)))
同样下面的语句我们也稍微修改一下:
output.write(enc_value)
修改为:
if enc_value != None:
output.write(enc_value)