Python-編寫1個Memcached的命令列

發表於2016-07-03

近期在專案中使用到了Memcached,相比redis較為齊全的工具,這個非關係型資料庫客戶端只能通過telnet與伺服器端進行互動,於是有了為這個資料編寫1個簡便的客戶端工具的想法。

如果你使用過redis提供的redis-cli,你會發現這個工具是多麼的方便,比如某個命令你忘記了其使用的方式,你可以通過如下的方式來檢視:

目標

於是,打算參考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類的例項。

之後,我們需要對使用者輸入的內容進行解析並呼叫其對應的方法。這方面,cmd模組已經幫助處理這方面的內容了,我們只需要在該類中實現1個do_*的方法,當我們在命令中輸入的1個對應的命令時,比如hello,其將呼叫1個do_hello的方法。
我們知道,在Memcached中有多個命令,如果我們對這些命令1個個的實現,不是1件容易的事情。比如,在memcached中有1個get方法用於獲取指定鍵名的數值,而在pymemcache的實現中,Client例項有1個get方法對應上述的這個指令。
因此,在這裡,我們採用動態獲取屬性的方式來簡化的工作量,即通過如下的方式來呼叫對應的get方法:

我們將這個屬性的處理過程封裝在1個get_action的方法中:

在這裡,我們遍歷Client類例項的每個屬性,如果對應的屬性不以_字元開頭,我們則獲取該屬性,如果該屬性可以呼叫,我們再進行屬性的設定,將其設定為該類的do_*屬性,通過該類_make_cmd方法返回對應的數值。
在這裡,我們將生成的cmd命令封裝在_make_cmd中,在這裡我們將通過name屬性獲取到使用者在命令列中輸入的第1個引數:

在這裡我們需要對傳入的字串進行切分。比如,使用者輸入了set name 20,那麼後面2個引數將以字串name 20的形式傳入。之後,我們嘗試獲取Client類的該屬性,並傳入解包後的引數進行呼叫。如果傳入的引數不正確,將觸發1個異常而被捕獲,並直接輸出。最後,我們返回1個handler函式。
這樣,當我們輸入如下的命令時:

這將呼叫Client例項的set方法,並將name和20以引數的形式傳入,從而實現設定對應鍵名及其鍵值。
這樣,我們就完成了我們前3個思路的工作。關於命令幫助的問題,在Python中存在1個docstring的東西,我們可以直接使用該類每個方法的__doc__屬性來實現對其文件的獲取。而在cmd中提供了help_*的方法來實現對某個命令幫助文件的呼叫。
而在pymemcache庫中這方面已經幫助我們做好了,因此我們可以直接使用,我們只需要在之前的get_action方法中新增這麼幾行程式碼:

我們將其進行判斷得到的對應文件是否為空字串,如果不是才設定其對應的方法。我將幫助文件的內容封裝在了1個_make_help的方法中:

在這裡,我們直接輸出文件的內容即可。
最後,我們來看實際的效果,首先是help列出所有可用的命令:

然後是獲取某個指令的說明:

最後是獲取和設定對應的鍵值:

由於時間的限制,有一些細節的功能就不一一實現了。最後,可以通過如下的方式安裝使用:

參考文章:

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

相關文章