PyCharm插件开发实践之PyGetterAndSetter详解

背景需求

在面向对象的设计中,典型如Java语言,为了控制对象属性的修改入口,我们常用的做法是把属性设置为private,然后通过getter和setter方法访问、修改该属性。

但是在Python语言中,并没有Java的访问控制符,对象的属性可以直接访问、修改。

为了良好的设计规范,我们可以规定,在Python类中,所有的对象属性均以下划线"_"前缀开头,同时编写该属性的getter和setter方法,在其他地方引用的时候,禁止出现直接引用。

在IDEA等IDE中,可以对Java的对象属性直接生成getter和setter方法,但是针对Python没有这样的功能。大量的getter和setter方法,很耗费精力,所以需要一款插件来辅助自动化生成Python对象属性的getter和setter方法。

搭建环境

编写IDEA系列的插件开发环境,可以看我之前的一篇文章:《IntelliJ IDEA/Android Studio插件开发指南》

官方开发文档:IntelliJ Platform SDK

过程拆解

Python文件例子:

class Test(object):
     def __init__(self):
         self._var1 = ""
         self._var2 = 0

明确了需求、输入(python对象属性定义代码)、输出(PyCharm插件自动生成getter和setter)后,我们针对这个插件的流程进行拆解:

  1. 首先,用户选中了对应行的文本内容,插件获取到该内容文本
  2. 在内容文本中过滤出变量,在本例中,就是过滤出_var1, _var2
  3. 拼装变量的getter和setter方法
  4. 计算出要插入的位置
  5. 回写到编辑器中

1. 获取文本

在PyCharm插件中,Editor对象是编辑器的总览,其中包含很多Model,比如

CaretModel caretModel=editor.getCaretModel(); // 用于描述插入光标
SelectionModel selectionModel = editor.getSelectionModel();  // 用于描述选中的文本
FoldingModel foldingModel = editor.getFoldingModel();  // 用于描述代码折叠区域
IndentsModel indentModel = editor.getIndentsModel();  // 用于描述缩进
……

在这里,我们只需要SelectionModel。

// 获取光标选中文本段对象
        SelectionModel selectionModel = editor.getSelectionModel();
        // 拿到选中部分字符串
        String selectedText = selectionModel.getSelectedText();

2. 正则匹配

拿到选中文本后,有可能选择了多行,里面包含多个变量,所以我们需要获取到变量列表。
观察到所有的变量都是self.abc=xxx的模式,我们可以考虑用正则匹配把其中的abc获取到。
Java中负责正则匹配并获取匹配字符串的类是PatternMatcher

  /**
     * 获取选中文本中所有的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方法都非常简单,我们可以先创造一个模板:

// 定义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的缩进,我这里使用的4个空格做缩进,如果你使用两个空格的话,在这里修改成两个空格即可。
在这里不能使用\t,我尝试了\t,在PyCharm中无法自动转换为4个空格,会报错。

上一步获取到的变量,有可能不存在下换线前缀,也有可能存在1个或者2个下划线前缀,比如var,_var,__var,他们对应的gett和setter如下:

# 假如变量为_var
def get_var(self):
    return self._var;

def set_var(self, var):
    self._var = var;

可以看到在self.xxx中需要使用变量,而在get_xxx和setter的参数中,需要删除对应的下划线。所以有:

   ……
        // 对于 “_value” 类型的变量,在set方法参数中,只需要“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. 计算位置

首先需要获取到Document对象,这是负责描述文档的,里面有很多负责文档的方法,比如在文件中插入字符串,计算文件行数,计算文档长度,删除相应内容等等。

Document document = editor.getDocument();

为了方便简单,我们设定在选中文本的下一行生成getter和setter。

   // 得到选中字符串的结束位置
        int endOffset = selectionModel.getSelectionEnd();
        // 得到最大插入字符串(生成的Getter和Setter函数字符串)的位置
        int maxOffset = document.getTextLength();
        // 计算选中字符串所在的行号,通过行号得到下一行的第一个字符的起始偏移量
        int curLineNumber = document.getLineNumber(endOffset);
        int docLineCount = document.getLineCount();
        // 如果目前文件行数不足以支持选中文本的下一行,也就是选中文本包含最后一行,就插入一个空行
        if (docLineCount - 1 < curLineNumber + 1) {
            Runnable runnable = () -> document.insertString(maxOffset,"\n");
            WriteCommandAction.runWriteCommandAction(project, runnable);
        }
        int nextLineStartOffset = document.getLineStartOffset(curLineNumber + 1);

5. 回写

将字符串插入文档中,不能直接使用document.insertString,会error: Assertion failed: Write access is allowed inside write-action only (see com.intellij.openapi.application.Application.runWriteAction())

需要把这个任务放入一个Runnable中,然后由WriteCommandAction来调度。

参考:Write access is allowed inside write-action only

 // 对文档进行操作部分代码,需要放入runnable,不然IDEA会卡住
        Runnable runnable = () -> document.insertString(nextLineStartOffset, genGetterAndGetter(fieldList));

        // 加入任务,由IDE调度任务
        WriteCommandAction.runWriteCommandAction(project, runnable);

效果

目前来看效果还不错,关于安装方法、使用方法,见github的README。

资源

github链接:https://github.com/mybichu/PyGetterAndSetter

到此这篇关于PyCharm插件开发实践之PyGetterAndSetter详解的文章就介绍到这了,更多相关PyCharm插件开发内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Pycharm 安装 idea VIM插件的图文教程详解

    直接在线安装 1.File->Settings->Plugins->Install JetBrains Plugins 2.点击install安装ideavim 3.也许需要的切换vim模式和pychar模式 快捷键:Ctrl+Alt+V 也许需要的方法二:手动导入 插件地址:http://plugins.jetbrains.com/plugin/?ruby&id=164File->Settings->Plugins->Install plugin from d

  • Pycharm和Idea支持的vim插件的方法

    Ideavim对同时喜欢Vim和Intellij全家桶(Idea, Pycharm等)的人来说是再熟悉不过了,既可以享受Intellij的强大功能,又可以用Vim操作文本,真是双份的快乐.可是你知道Ideavim也有插件的吗,虽然是官方模拟的,但操作方式与Vim原生的并没有什么不同?从IdeaVim的主页上可以查到支持的插件列表. easymotion 模拟的是Vim-easymotion插件 需要事先安装IdeaVim-EasyMotion和AceJump这两个Idea的插件. 使用方法:<l

  • PyCharm安装Markdown插件的两种方法

    Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. 从github下载的代码一般都会带有README.md文件,该文件是一个Markdown格式的文件.PyCharm是默认没有安装Markdown插件的,所以不能按照Markdown格式显示文本,显示的是原始文本.下面已github库PyWatchlog的代码为例介绍两种安装Markdown的方法. 方法一: 在PyCharm打开PyWatchlog工程后打开README.md文件

  • PyCharm配置mongo插件的方法

    一.安装mongo plugs插件 File->Setting Plugins查询Mongo选择Search in repositories 选择Mongo plugins,选择install 然后重启pycharm,Restart PyCharm就完成了mongo插件的安转 2.配置mongo插件 选择View->ToolButton 在pycharm的右边可以看到,选择扳手标志 选择绿色加号按钮出现Add a mongo server,输入label即可,也可设置用户名和密码: 选择ok后

  • PyCharm插件开发实践之PyGetterAndSetter详解

    背景需求 在面向对象的设计中,典型如Java语言,为了控制对象属性的修改入口,我们常用的做法是把属性设置为private,然后通过getter和setter方法访问.修改该属性. 但是在Python语言中,并没有Java的访问控制符,对象的属性可以直接访问.修改. 为了良好的设计规范,我们可以规定,在Python类中,所有的对象属性均以下划线"_"前缀开头,同时编写该属性的getter和setter方法,在其他地方引用的时候,禁止出现直接引用. 在IDEA等IDE中,可以对Java的对

  • Python解释器以及PyCharm的安装教程图文详解

    本文给大家分享Python解释器安装以及PyCharm安装过程.很多朋友问小编要完整的安装教程,现分享给大家. 一.Python解释器安装 解释器(英语:Interpreter),又译为直译器,是一种电脑程序能够把高级编程语言一行一行直接转译运行.解释器不会一次把整个程序转译出来,只像一位"中间人",每次运行程序时都要先转成另一种语言再作运行,因此解释器的程序运行速度比较缓慢.它每转译一行程序叙述就立刻运行,然后再转译下一行,再运行,如此不停地进行下去. Python的下载网站:Pyt

  • Windows+Anaconda3+PyTorch+PyCharm的安装教程图文详解

    1. 安装Anaconda3 官网下载Anaconda3:https://www.anaconda.com/distribution/ 运行下载好的.exe文件 Win+R 调出运行对话框,输入 cmd 回车,输入 python,如果出现python版本信息,表明安装成功. 添加环境变量:高级系统设置 -> 环境变量 2. 查看电脑显卡信息 以 Win10 为例,控制面板 -> NVIDIA控制面板 -> 帮助 -> 系统信息 -> 组件 3. 创建PyTorch环境 卸载原

  • Windows下Anaconda和PyCharm的安装与使用详解

    1. Anaconda (下面都是一些口水话,可以稍微了解一下,不必过于斟酌��)   Anaconda是将Python和许多常用的package(Python开源包)打包直接来使用的Python发行版本,支持Windows.Linux和macOS系统,并有一个conda(开源包packages和虚拟环境environment的管理系统)强大的执行工具.   Anaconda的优点总结起来就八个字:省时省心.分析利器.   省时省心: Anaconda通过管理工具包.开发环境.Python版本,

  • Pycharm新手使用教程(图文详解)

    [注]:如果想要下载Pycharm工具,直接去<开发工具>中进行下载. 简介 Jetbrains家族和Pycharm版本划分: pycharm是Jetbrains家族中的一个明星产品,Jetbrains开发了许多好用的编辑器,包括Java编辑器(IntelliJ IDEA).JavaScript编辑器(WebStorm).PHP编辑器(PHPStorm).Ruby编辑器(RubyMine).C和C++编辑器(CLion)..Net编辑器(Rider).iOS/macOS编辑器(AppCode)

  • 如何使用pycharm连接Databricks的步骤详解

    在本地使用pycharm连接databricks,大致步骤如下: 首先,为了让本地环境能够识别远端的databricks集群环境,需要收集databricks的基本信息和自己databricks的token,这些信息能够让本地环境识别databricks:接着,需要使用到工具 anaconda创建一个虚拟环境,连接databricks:最后,将虚拟环境导入pycharm. (下面的图渣渣,因为直接拖进来的) 第0步:检查 检查java版本,需要时1.8开头的版本,如果不是,请到这里下载:http

  • pycharm指定python路径过程详解

    pycharm指定python路径,pycharm配置python环境的方法是: 1.依次点击[File].[Project Interpreter]: 2.点击[Show All],选择[Existing Environment]: 3.选择python的安装路径,点击OK即可. pycharm如何设置python路径 解释器的选项路径为:File->Setting->Build, Execution, Deployment-> Console-> Python Console:

  • Babel 插件开发&访问节点实例详解

    目录 访问节点 获取子节点的Path: 检查节点的类型: 检查路径(Path)类型: 检查标识符(Identifier)是否被引用: 找到特定的父路径: 获取同级路径: 停止遍历: 访问节点 获取子节点的Path: 我们在处理节点的属性之前必须要拿到节点对象才能进行操作,我们使用path.node.property来访问属性~ BinaryExpression(path) { path.node.left; path.node.right; path.node.operator; } 我们还可以

  • jquery插件开发之选项卡制作详解

    在jquery中,插件开发常见的有: 一种是为$函数本身扩展一个方法,这种是静态扩展(也叫类扩展),这种插件一般是工具方法, 还有一种是扩展在原型对象$.fn上面的,开发出来的插件是用在dom元素上面的 一.类级别的扩展 $.showMsg = function(){ alert('hello,welcome to study jquery plugin dev'); } // $.showMsg(); 注意要提前引入jquery库, 上例在$函数上面添加了一个方法showMsg,那么就可以用$

  • JavaScript继承的特性与实践应用深入详解

    本文详细讲述了JavaScript继承的特性与实践应用.分享给大家供大家参考,具体如下: 继承是代码重用的模式.JavaScript 可以模拟基于类的模式,还支持其它更具表现力的模式.但保持简单通常是最好的策略. JavaScript 是基于原型的语言,也就是说它可以直接继承其他对象. 1 伪类 JavaScript 的原型不是直接让对象从其他对象继承,而是插入一个多余的间接层:通过构造函数来产生对象. 当一个函数被创建时,Function 构造器产生的函数对象会运行这样类似的代码: this.

随机推荐