史上最暴力程序媛

(零)

 

这个暑假我跟着本校的计算机教授做研究(research),就不回中国不回杭州了。

 

圣路易斯的夏天超级热,这两天气温一直在九十五华氏度左右,我不禁怀念起那北纬四十度的俄亥俄清风拂过村头的清凉。

 

而比天气还热的,是写得正热火朝天的代码。

 

我放假后休息了一星期用来搬家,之后便开始朝九晚五地工作。我有一个办公室,是一个挂着我名字的小隔间;我还有一个队友,是来自俄亥俄北部的女生Kimmy。

 

欣妈:“啥,她是你老乡啊?”

欣欣:“…亲妈你别闹。”

 

我刚来上班的时候,Kimmy已经在写用户界面(user interface)了,我也见证了她把主流语言试了个遍,从php到Java再到Python。我呢,看书为主,几乎每天学一样:SAS,Java Swing,XML,等等。

 

自从上星期Kimmy回俄亥俄以后,继续写用户界面的重任就交到了我手里。虽然我一点也不会写Python,可教授觉得我会,那我就会一下吧。

 

(一)

 

第一天我没有看代码也没有写代码。看掉了一份两百页的教程,过了一本四百页的书。

 

第二天我要开始写了。头皮发麻。硬上。
(二)

 

我打开写一半的代码,打算先运行看结果,结果什么都没运行出来。只见屏幕中央一个四四方方的白色方块,旋转的鼠标显示系统繁忙。我跑去问教授怎么回事。

 

教授:“刚我也以为这个代码有问题,后来Kimmy说这个是因为导入的包比较大,第一次运行大概要加载半小时。”

我:“呃。”

 

原来,代码直接import加一个星号,通配符把文件夹下大大小小所有的文件通通导进了程序。想想还是挺搞笑的,于是我一边笑一边开着窗口做别的事情。

 

 

笑了两小时,我笑不出来了。屏幕还是什么都没有。

 

教授对代码进行了一些改动,根据Qt的当前版本修改了一些写法;我也想办法精简import语句,只导入需要用到的那几个类。

 

周四的早上,代码终于能运行了。那是一个下拉菜单,跟着四个满是复选框的区域,每个区域还带一个“更多(more)”的按钮。非常漂亮。

 

(三)

 

我的第一个任务是,把代码改成循环(loop)的形式。

 

原先的代码生成的屏幕挂件(widget)是特定的,要增加新的挂件需要复制粘贴已有的代码。在研究的第一阶段,只能大致估计研究需要四个分类,每个分类下都要显示一个复选框(multiple choice group box)。原代码于是定义了box1、box2、box3、box4四个变量,所有与之相关的内容也都是这样命名的。

 

我于是定义了一个叫numOfCat的变量,表示一共有多少个分类,在程序的一开始赋值成等于四。又把每样四个头的东西都定义成动态的数组(list),再用大大小小各种循环来做原先要做的事情。这样,四个box开头的变量就变成了box[1]、box[2]、box[3]、box[4]。只要修改numOfCat的值,就能很方便地增加或减少屏幕挂件的个数。

 

然后我开始写文件读入。我写的这个程序要读入一个类似于这样的文本文件:

 

<variables>
<分类 1>
第1个复选框的第1个选项的文字
第1个复选框的第2个选项的文字
第1个复选框的第3个选项的文字
</分类1>
<分类 2>
第1个复选框的第1个选项的文字
第1个复选框的第2个选项的文字
</分类2>

</variables>

 

读进来是什么,复选框的文字便相应地显示什么。用尖括号括起来的标签相当于分隔符,是用来隔开上下相邻的分类的,有特殊的意义。我用一个动态的二维数组来储存这些字符串,数组的第一维对应不同的分类,第二维对应每个分类下不同的选项。我还增加了各种检测,确保读进来的数据是正确的格式,找不到文件的时候会给出警告。

 

写完这个,我发现numOfCat也可以不需要手动指定了,程序读出几个标签numOfCat就是几。好处是,不用修改程序源码,不用担心索引越界。

 

以上这些都不难,充其量帮我熟悉了Python的基本语法。接下来的几样才叫头疼。

 

(四)

 

关于用户界面,据说Python自带的包非常弱,所以Kimmy用的是基于Qt5的guidata。这个东西虽然很高级,用起来也很坑,网上能搜到的相关资料并不多,主要得自己去开发者文档里找调用它的写法。问题是,开发者文档都很难找,要很认真地找才能在谷歌的某个角落翻出来。而且,这个文档写得非常简略,还不如直接看源码。

 

靠着Qt的文档和guidata的源码,我着手对界面的大改造。

 

教授说,原代码生成的四个复选框,连着四个滚动条,看着不够清晰方便,最好能改成只有一个滚动条。

 

我定睛一看,原代码的界面的结构是这样的:主窗口绑定了一个splitter类的容器,里面装着四个复选框,由splitter来智能调整大小;滚动条和复选框是一对一绑定的,显然滚动条不能直接绑定多个复选框。

 

在那个周五的下午,我喝牛奶的时候灵光一现,想出了小splitter嵌套进主splitter的方法。我看到有个网友一个水平方向的splitter里嵌了好两个竖直方向的splitter,我觉得他嵌这么多都可行,那我嵌一个总没问题吧。

 

然后,我就去吃韩国烤肉了。

 

星期一回办公室,我成功地把四个滚动条变成了一个。小splitter绑定一个滚动条,再把四个复选框都丢进这个小splitter。即使两个splitter是同方向的,它们还是可以自动调整到合适的大小。主splitter的其它挂件也不会受到滚动条的影响。

 

超开心。
(五)

 

我从教授那里得到一本Python的书,一千多页,最后一章讲的是元类(metaclass)。书里说,百分之九十九的人用不到它。我要加一句,剩下那百分之一,用到的都哭瞎了。

 

我就是那百分之一。

 

有个问题从我接手代码的时候就产生了。guidata如果要生成一个复选框,需要传入一个参数来指定复选框里的内容。反人类的是,这个参数是一个继承DataSet的类(class),而不是这个类的实例(instance)。

 

原代码定义了四个类,又写了四行语句来生成四个复选框。我在改写成循环时,暂时简化为传入同一个类。四个复选框显示的文字一模一样,而我回头修改才发现这看似容易的最后一步,没有我想象的那么简单。

 

有多少个复选框,就需要多少个对应的类。所以,在分类的数量numOfCat变成动态的那一刻起,我没法提前预知类的数量,也就必须动态生成新的类。注意是类本身,而不是同一个类的实例。这就是为什么我尝试给这个类传入额外参数、试图指定复选框内容的时候,会得到一堆运行错误。我需要用新的知识,来解决这个难题。

 

我一时找不到答案,于是漫无目的地翻着教授那本书的目录。

 

由于中文相关资料比较少,我搜索和使用的所有资料都是英文的,包括那本书。当我看到元类(metaclass)那一章,标题的“meta”让我眼前一亮。这个英文词根的有“超越”的意思,比如“metamorphic”是“形而上的”。“metaclass”顾名思义,大概是超越了类本身的限制,凌驾于类原本框架的高级类。

 

我看到章节开头那句警告:“如果你在思考你到底需不需要元类,那就别用了,因为你正在思考的行为说明你其实并不需要它。”我心想,我思考是因为我第一次见到这玩意儿。当我看到元类的适用范围包括“根据用户输入,动态生成一些类”的时候,我几乎可以确定,我需要的就是它。

 

我觉得我是史上最暴力的程序员了,在学习Python的第六天,用元类强行造出一堆类,再用类里的一堆字符串数组造复选框。难题解决。
(六)

 

我写代码一直注重可扩展性。早年编写游戏的经历告诉我,如果想要在日后增加新功能时少费周折,那么写第一个版本时便要将可扩展性铭记于心。

 

我定义numOfCat的初衷便是如此。现在有四个分类不代表以后真正开始处理数据时也是四个分类,实验室的另一头,两个男生还在不断整理出新的数据文件,我手上的这些信息随时可能变化。我改写后的程序,只要输入文件(input)是正确的格式,无需我改动一丝一毫就能读入包含任意数量分类的文件。

 

除此之外,我还做了其它一些改动。我把读入文件的几十行语句抽离成一个函数,只要把文件名传入这个函数,它就会返回一个带着所有复选框选项文字的二维数组,我的程序可以在未来干净地读入多个文件。甚至,在教授说每个选项都有两个别名时,我轻松地给数组增加了一个维度,只修改这个函数的内容,便达到了想要的效果。

 

我还把那几个复选框装进一个我自己写的继承滚动条区域(ScrollArea)的类,进一步优化了代码结构。
(七)

 

一星期过去了,程序最重要的功能却没有解决。每天,我绞尽脑汁,却还没有发现可行的方法。

 

这个功能是什么,我又将会如何解决呢?等待我的下一个挑战是什么?除了研究,我空余时间又在忙些什么?

 

请待下回分解。

(溜走)

评论区

  1. 阿斯顿 2020年1月7日 回复

    牛b

  2. 鑫鑫财经 2019年4月11日 回复

    努力了 看不懂哈哈哈哈

  3. 张小飞 2018年7月17日 回复

    哈哈哈,努力的看完了

  4. 梨子 2017年9月22日 回复

    py写UI?不!我觉得我脑壳会痛,爪子也会痛!PHP来吧!

  5. 减肥快招 2017年3月22日 回复

    做码农不容易啊

  6. 青岛礼品 2016年8月11日 回复

    高效率

  7. lightxu 2016年8月3日 回复

    用python写UI真是作了个大死啊lol (咦有阿狸表情包好评!){smile:12}

  8. themebetter 2016年7月18日 回复

    挺厉害,这学习速度。

  9. 独立思考网 2016年6月30日 回复

    学习效率挺高的,佩服。

  10. 长风 2016年6月23日 回复

    偶然看见,不错!

  11. raintrue 2016年6月21日 回复

    刚刚在同事面前介绍欣欣做的游戏来着,就进来了

    • 甜菜欣欣 2016年6月21日 回复

      @raintrue:好开心^_^
      赶紧进屋,给你搬个小板凳

  12. 风情 2016年6月19日 回复

    码农~~~ 好辛苦的说

发表回复

您的电子邮箱地址不会被公开。