PyCharm插件開發(fā)實(shí)踐之PyGetterAndSetter詳解
背景需求
在面向?qū)ο蟮脑O(shè)計(jì)中,典型如Java語(yǔ)言,為了控制對(duì)象屬性的修改入口,我們常用的做法是把屬性設(shè)置為private,然后通過(guò)getter和setter方法訪問(wèn)、修改該屬性。
但是在Python語(yǔ)言中,并沒(méi)有Java的訪問(wèn)控制符,對(duì)象的屬性可以直接訪問(wèn)、修改。
為了良好的設(shè)計(jì)規(guī)范,我們可以規(guī)定,在Python類中,所有的對(duì)象屬性均以下劃線"_"前綴開頭,同時(shí)編寫該屬性的getter和setter方法,在其他地方引用的時(shí)候,禁止出現(xiàn)直接引用。
在IDEA等IDE中,可以對(duì)Java的對(duì)象屬性直接生成getter和setter方法,但是針對(duì)Python沒(méi)有這樣的功能。大量的getter和setter方法,很耗費(fèi)精力,所以需要一款插件來(lái)輔助自動(dòng)化生成Python對(duì)象屬性的getter和setter方法。
搭建環(huán)境
編寫IDEA系列的插件開發(fā)環(huán)境,可以看我之前的一篇文章:《IntelliJ IDEA/Android Studio插件開發(fā)指南》
官方開發(fā)文檔:IntelliJ Platform SDK
過(guò)程拆解
Python文件例子:
class Test(object):
def __init__(self):
self._var1 = ""
self._var2 = 0
明確了需求、輸入(python對(duì)象屬性定義代碼)、輸出(PyCharm插件自動(dòng)生成getter和setter)后,我們針對(duì)這個(gè)插件的流程進(jìn)行拆解:
- 首先,用戶選中了對(duì)應(yīng)行的文本內(nèi)容,插件獲取到該內(nèi)容文本
- 在內(nèi)容文本中過(guò)濾出變量,在本例中,就是過(guò)濾出_var1, _var2
- 拼裝變量的getter和setter方法
- 計(jì)算出要插入的位置
- 回寫到編輯器中
1. 獲取文本
在PyCharm插件中,Editor對(duì)象是編輯器的總覽,其中包含很多Model,比如
CaretModel caretModel=editor.getCaretModel(); // 用于描述插入光標(biāo) SelectionModel selectionModel = editor.getSelectionModel(); // 用于描述選中的文本 FoldingModel foldingModel = editor.getFoldingModel(); // 用于描述代碼折疊區(qū)域 IndentsModel indentModel = editor.getIndentsModel(); // 用于描述縮進(jìn) ……
在這里,我們只需要SelectionModel。
// 獲取光標(biāo)選中文本段對(duì)象
SelectionModel selectionModel = editor.getSelectionModel();
// 拿到選中部分字符串
String selectedText = selectionModel.getSelectedText();
2. 正則匹配
拿到選中文本后,有可能選擇了多行,里面包含多個(gè)變量,所以我們需要獲取到變量列表。
觀察到所有的變量都是self.abc=xxx的模式,我們可以考慮用正則匹配把其中的abc獲取到。
Java中負(fù)責(zé)正則匹配并獲取匹配字符串的類是Pattern和Matcher。
/**
* 獲取選中文本中所有的self.value中的value <br>
* e.g. self.value = xxx,or self._value = xxx, <br>
* 可以獲取到其中的value
*
* @param selectedText 選中文本
* @return 變量字符串列表
*/
public ArrayList<String> getFieldList(String selectedText) {
ArrayList<String> list = new ArrayList<>();
// 刪除所有空格
selectedText = selectedText.replaceAll(" ", "");
// 正則匹配獲得變量字符串
String reg = "self.(.*?)=";
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(selectedText);
while (matcher.find()) {
list.add(matcher.group(1));
}
return list;
}
3. 拼裝方法
Python中的getter和setter方法都非常簡(jiǎn)單,我們可以先創(chuàng)造一個(gè)模板:
// 定義Getter和Setter的模板
String getterTemplate = " def get_word(self):\n return self.field\n ";
String setterTemplate = " def set_word(self, word):\n self.field = word\n ";
之所以存在空格,是為了匹配PyCharm的縮進(jìn),我這里使用的4個(gè)空格做縮進(jìn),如果你使用兩個(gè)空格的話,在這里修改成兩個(gè)空格即可。
在這里不能使用\t,我嘗試了\t,在PyCharm中無(wú)法自動(dòng)轉(zhuǎn)換為4個(gè)空格,會(huì)報(bào)錯(cuò)。
上一步獲取到的變量,有可能不存在下?lián)Q線前綴,也有可能存在1個(gè)或者2個(gè)下劃線前綴,比如var,_var,__var,他們對(duì)應(yīng)的gett和setter如下:
# 假如變量為_var
def get_var(self):
return self._var;
def set_var(self, var):
self._var = var;
可以看到在self.xxx中需要使用變量,而在get_xxx和setter的參數(shù)中,需要?jiǎng)h除對(duì)應(yīng)的下劃線。所以有:
……
// 對(duì)于 “_value” 類型的變量,在set方法參數(shù)中,只需要“value”
for (String field : fieldList) {
String tmp = field;
int i = 0;
while (tmp.charAt(i) == '_') {
tmp = tmp.substring(1);
}
// 替換掉模板中的變量
String customGetter = getterTemplate.replaceAll("word", tmp).replaceAll("field", field);
String customSetter = setterTemplate.replaceAll("word", tmp).replaceAll("field", field);
stringBuilder.append("\n").append(customGetter).append("\n").append(customSetter);
}
……
4. 計(jì)算位置
首先需要獲取到Document對(duì)象,這是負(fù)責(zé)描述文檔的,里面有很多負(fù)責(zé)文檔的方法,比如在文件中插入字符串,計(jì)算文件行數(shù),計(jì)算文檔長(zhǎng)度,刪除相應(yīng)內(nèi)容等等。
Document document = editor.getDocument();
為了方便簡(jiǎn)單,我們?cè)O(shè)定在選中文本的下一行生成getter和setter。
// 得到選中字符串的結(jié)束位置
int endOffset = selectionModel.getSelectionEnd();
// 得到最大插入字符串(生成的Getter和Setter函數(shù)字符串)的位置
int maxOffset = document.getTextLength();
// 計(jì)算選中字符串所在的行號(hào),通過(guò)行號(hào)得到下一行的第一個(gè)字符的起始偏移量
int curLineNumber = document.getLineNumber(endOffset);
int docLineCount = document.getLineCount();
// 如果目前文件行數(shù)不足以支持選中文本的下一行,也就是選中文本包含最后一行,就插入一個(gè)空行
if (docLineCount - 1 < curLineNumber + 1) {
Runnable runnable = () -> document.insertString(maxOffset,"\n");
WriteCommandAction.runWriteCommandAction(project, runnable);
}
int nextLineStartOffset = document.getLineStartOffset(curLineNumber + 1);
5. 回寫
將字符串插入文檔中,不能直接使用document.insertString,會(huì)error: Assertion failed: Write access is allowed inside write-action only (see com.intellij.openapi.application.Application.runWriteAction())
需要把這個(gè)任務(wù)放入一個(gè)Runnable中,然后由WriteCommandAction來(lái)調(diào)度。
參考:Write access is allowed inside write-action only
// 對(duì)文檔進(jìn)行操作部分代碼,需要放入runnable,不然IDEA會(huì)卡住
Runnable runnable = () -> document.insertString(nextLineStartOffset, genGetterAndGetter(fieldList));
// 加入任務(wù),由IDE調(diào)度任務(wù)
WriteCommandAction.runWriteCommandAction(project, runnable);
效果
目前來(lái)看效果還不錯(cuò),關(guān)于安裝方法、使用方法,見github的README。

資源
github鏈接:https://github.com/mybichu/PyGetterAndSetter
到此這篇關(guān)于PyCharm插件開發(fā)實(shí)踐之PyGetterAndSetter詳解的文章就介紹到這了,更多相關(guān)PyCharm插件開發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python-for循環(huán)的內(nèi)部機(jī)制
這篇文章主要介紹了Python for循環(huán)的內(nèi)部機(jī)制,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
學(xué)習(xí)python需要有編程基礎(chǔ)嗎
在本篇文章里小編給大家分享的是一篇關(guān)于學(xué)習(xí)python有哪些必要條件,需要的朋友們可以學(xué)習(xí)下。2020-06-06
python圖片剪裁代碼(圖片按四個(gè)點(diǎn)坐標(biāo)剪裁)
這篇文章主要介紹了python圖片剪裁代碼(圖片按四個(gè)點(diǎn)坐標(biāo)剪裁),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
python?HTTP協(xié)議相關(guān)庫(kù)requests urllib基礎(chǔ)學(xué)習(xí)
這篇文章主要介紹了python?HTTP協(xié)議相關(guān)庫(kù)requests urllib基礎(chǔ)學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Python實(shí)現(xiàn)的多線程同步與互斥鎖功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)的多線程同步與互斥鎖功能,涉及Python多線程及鎖機(jī)制相關(guān)操作技巧,需要的朋友可以參考下2017-11-11
python如何通過(guò)twisted實(shí)現(xiàn)數(shù)據(jù)庫(kù)異步插入
這篇文章主要為大家詳細(xì)介紹了python如何通過(guò)twisted實(shí)現(xiàn)數(shù)據(jù)庫(kù)異步插入,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
如何在Python里使用ChatGPT及ChatGPT簡(jiǎn)介
今年最火的應(yīng)該就是ChatGPT了,現(xiàn)在短短2個(gè)月已經(jīng)突破了1億注冊(cè)用戶,馬斯克可高興壞了,這篇文章主要介紹了如何在Python里使用ChatGPT及ChatGPT是什么?注冊(cè)方式?需要的朋友可以參考下2023-02-02
Python中查看變量的類型內(nèi)存地址所占字節(jié)的大小
這篇文章主要介紹了Python中查看變量的類型,內(nèi)存地址,所占字節(jié)的大小,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06
python 實(shí)現(xiàn)樸素貝葉斯算法的示例
這篇文章主要介紹了python實(shí)現(xiàn)樸素貝葉斯算法的示例,幫助大家更好的理解和學(xué)習(xí)python 機(jī)器學(xué)習(xí)算法,感興趣的朋友可以了解下2020-09-09
python 判斷一組數(shù)據(jù)是否符合正態(tài)分布
這篇文章主要介紹了python 如何判斷一組數(shù)據(jù)是否符合正態(tài)分布,幫助大家更好的利用python分析數(shù)據(jù),感興趣的朋友可以了解下2020-09-09

