资讯专栏INFORMATION COLUMN

使用 Python 编写一个 Memcached 的 CLI

aisuhua / 1151人阅读

摘要:原文地址近期在项目中使用到了相比较为齐全的工具这个非关系型数据库客户端只能通过与服务器端进行交互于是有了为这个数据编写个简便的客户端工具的想法。如果用户没有传入对应的参数则使用默认的参数进行绑定。

原文地址:

http://52sox.com/use-python-write-a-memcached-cli/

近期在项目中使用到了Memcached,相比redis较为齐全的工具,这个非关系型数据库客户端只能通过telnet与服务器端进行交互,于是有了为这个数据编写1个简便的客户端工具的想法。
如果你使用过redis提供的redis-cli,你会发现这个工具是多么的方便,比如某个命令你忘记了其使用的方式,你可以通过如下的方式来查看:

 127.0.0.1:6379> help get

  GET key
  summary: Get the value of a key
  since: 1.0.0
  group: string
目标

于是,打算参考redis-cli编写1个Memcached的CLI,在这个版本中,我们要实现:

输入正确命令和参数后立即返回对应的结果

1个提示帮助命令的功能

实现思路

为了实现这个命令行版本,我们需要考虑以下几个方面:

支持修改连接服务器的监听地址和端口

对传入的参数进行解析并调用对应的方法

调用对应命令并传入参数后,如果参数不对能给出错误的提示

支持帮助选项

对于第1个问题,我们可以通过参数的方式来解决。如果用户没有传入对应的参数,则使用默认的参数进行绑定。关于从命令行中解析参数的方式,Python提供了几种方式,这里我选用的是argparse模块来操作。
而对应后面3个问题,我们可以借助标准库中的cmd模块来实现。

选择客户端绑定

在Python的Memcached的客户端实现中,有python-memcachedpymemcache以及pylibmc等多种第3方库,这里我采用的是pymemcache来说明我们这个命令行的实现,主要原因在于它是纯python实现中最快和异常处理比较好的1个库。

实现

下面,我们正式开始实现这个命令行。由于我们一般不会直接实例化Cmd类。我们先定义1个MemcachedCLI类,这个类继承自cmd模块中的Cmd类。接着,我们会实例化1个Memcached类的实例。

from pymemcache.client.base import Client
from cmd import Cmd

class MemcachedCLI(Cmd):
    def __init__(self, host, port):
        self.client = Client((host, port))

之后,我们需要对用户输入的内容进行解析并调用其对应的方法。这方面,cmd模块已经帮助处理这方面的内容了,我们只需要在该类中实现1个do_*的方法,当我们在命令中输入的1个对应的命令时,比如hello,其将调用1个do_hello的方法。
我们知道,在Memcached中有多个命令,如果我们对这些命令1个个的实现,不是1件容易的事情。比如,在memcached中有1个get方法用于获取指定键名的数值,而在pymemcache的实现中,Client实例有1个get方法对应上述的这个指令。
因此,在这里,我们采用动态获取属性的方式来简化的工作量,即通过如下的方式来调用对应的get方法:

getattr(self.client,"get")

我们将这个属性的处理过程封装在1个get_action的方法中:

def get_action(self, client):
    for name in dir(client):
        if not name.startswith("_"):
            attr = getattr(client, name)
            if callback(attr):
                setattr(self.__class__, "do_" + name, self._make_cmd(name))

在这里,我们遍历Client类实例的每个属性,如果对应的属性不以_字符开头,我们则获取该属性,如果该属性可以调用,我们再进行属性的设置,将其设置为该类的do_*属性,通过该类_make_cmd方法返回对应的数值。
在这里,我们将生成的cmd命令封装在_make_cmd中,在这里我们将通过name属性获取到用户在命令行中输入的第1个参数:

    def _make_cmd(self, name):
        def handler(self, line):
            parts = line.split()
            try:
                print(getattr(self.client, name)( *parts))
            except Exception as e:
                print("Error:{0}".format(e))
        return handler

在这里我们需要对传入的字符串进行切分。比如,用户输入了set name 20,那么后面2个参数将以字符串name 20的形式传入。之后,我们尝试获取Client类的该属性,并传入解包后的参数进行调用。如果传入的参数不正确,将触发1个异常而被捕获,并直接输出。最后,我们返回1个handler函数。
这样,当我们输入如下的命令时:

set name 20

这将调用Client实例的set方法,并将name和20以参数的形式传入,从而实现设置对应键名及其键值。
这样,我们就完成了我们前3个思路的工作。关于命令帮助的问题,在Python中存在1个docstring的东西,我们可以直接使用该类每个方法的__doc__属性来实现对其文档的获取。而在cmd中提供了help_*的方法来实现对某个命令帮助文档的调用。
而在pymemcache库中这方面已经帮助我们做好了,因此我们可以直接使用,我们只需要在之前的get_action方法中添加这么几行代码:

doc = (getattr(attr, "__doc__", "") or "").strip()
if doc:
    setattr(self.__class__, "help_" + name, self._make_help(doc))

我们将其进行判断得到的对应文档是否为空字符串,如果不是才设置其对应的方法。我将帮助文档的内容封装在了1个_make_help的方法中:

    def _make_help(self, doc):
        def help(self):
            print(doc)
        return help

在这里,我们直接输出文档的内容即可。

总结

最后,我们来看实际的效果,首先是help列出所有可用的命令:

127.0.0.1:11211>help

Documented commands (type help ):
========================================
EOF     check_key  delete_many   get        gets_many  quit      set_multi
add     close      delete_multi  get_many   help       replace   stats    
append  decr       exit          get_multi  incr       set       touch    
cas     delete     flush_all     gets       prepend    set_many  version 

然后是获取某个指令的说明:

127.0.0.1:11211>help get

The memcached "get" command, but only for one key, as a convenience.

        Args:
          key: str, see class docs for details.

        Returns:
          The value for the key, or None if the key wasn"t found.

最后是获取和设置对应的键值:

127.0.0.1:11211>get name
None
127.0.0.1:11211>set name zhangsan
True
127.0.0.1:11211>get name
zhangsan

由于时间的限制,有一些细节的功能就不一一实现了。最后,可以通过如下的方式安装使用:

pip install memcached-cli

参考文章:

https://pymemcache.readthedocs.io/en/latest/apidoc/modules.html
https://tghw.com/blog/cheeky-python-a-redis-cli
https://docs.python.org/2/library/cmd.html#module-cmd

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38043.html

相关文章

  • 使用 Python 编写一个 Memcached CLI

    摘要:原文地址近期在项目中使用到了相比较为齐全的工具这个非关系型数据库客户端只能通过与服务器端进行交互于是有了为这个数据编写个简便的客户端工具的想法。如果用户没有传入对应的参数则使用默认的参数进行绑定。 原文地址: http://52sox.com/use-python-write-a-memcached-cli/ 近期在项目中使用到了Memcached,相比redis较为齐全的工具,这个非...

    RdouTyping 评论0 收藏0
  • 「真®全栈之路」Web前端开发后端指南

    前言 在若干次前的一场面试,面试官看我做过python爬虫/后端 的工作,顺带问了我些后端相关的问题:你觉得什么是后端? 送命题。当时脑瓦特了,答曰:逻辑处理和数据增删改查。。。 showImg(https://user-gold-cdn.xitu.io/2019/4/24/16a4ed4fc8c18078); 当场被怼得体无完肤,羞愧难当。事后再反思这问题,结合资料总结了一下。发现自己学过的Re...

    chuyao 评论0 收藏0
  • 天翼杯easy_eval复现

    摘要:最近打了很多比赛,很多题没有做出来。所以决定复现一下某些题目。至此,题目基本搭建完成。通过反序列化,触发函数。但需要注意的是函数会在这个类初始化之前触发。加载该文件,即可完成命令执行,访问到被限制访问的文件。 ...

    Channe 评论0 收藏0
  • 啊里云centos7.6编译安装NGINX+PHP7+MariaDB+MEMCACHED

    摘要:安装前准备修改默认主机名称安装依赖库删除系统默认数据库配置文件查询删除确认卸载系统自带查询删除安装数据库下载安装包解压创建数据库安装目录,数据存放目录, 安装前准备 修改默认主机名称 [root@iZuf60c5bxd15kr9gycvv6Z ~]# hostnamectl set-hostname centos [root@iZuf60c5bxd15kr9gycvv6Z ~]# re...

    yuanxin 评论0 收藏0
  • Docker快速搭建一套PHP、Nginx、MySQL、Redis、Xdebug、Memcached

    摘要:痛点如何简单迅速地初始化一个全新的开发环境呢笔者在尝试起一个新项目时,往往会陷入重新建立一套环境的繁琐事当中。架构本片文章搭建出来的环境如上图。网络这部分,为了便于配置就手动分配了。配置开启记录了一般性的查询日志,便于程序。 痛点 如何简单迅速地初始化一个全新的PHP开发环境呢? 笔者在尝试起一个新web项目时,往往会陷入重新建立一套Docker环境的繁琐事当中。我想大家在开始做一个新...

    VioletJack 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<