Shyaru II

春はあけぼの。

不过说起来,从来都是日上三竿才起的AS,也没有见过やうやう白くなりゆく山際以及紫だちたる雲の細くたなびきたる,似乎相当遗憾。

诸位好,这篇本来该是Shyaru的后端部分,不过我打算说说一些在做这部分的时候的一些副产品。

至于Shyaru本身,现在完成了基本算数运算,字符串运算,变量运算的部分。我姑且做了一些test,目前没发现有什么问题。

如果对Shyaru代码有兴趣,请移步Shyaru

大致就是这样。

首先我要解答上篇提到的,环境的设定需要在词法分析和文法分析的时候做么?

答案是不需要,词法分析只需要产生全局的词法表(这样来看,当时我给词法表取的名字是environment,这个名字并不适当),文法分析只需要老老实实产生AST就好。事实上,即使在文法分析阶段,引入了context,在真正解释的时候,这个context也很难拿到。即使能hack取到,也没什么裨益。

context是在解释的时候引入的,和前端关系不大。

所以我在parser上引入的,甚至打算进一步扩展的env,只是白费功夫。

如果您有兴趣看一下Shyaru的commit记录的话,您会发现有两次很重大的结构修改。

我试图说明一下这之中发生了什么。

第一次结构的修改,是为了引入包,以及尝试利用__init__.py文件来组织散乱的代码。

当然引入包没什么不好,但是问题在于其实当时我对包的特性所知甚少,直接导致了昨天的第三次代码结构修改。

在第一次结构修改的时候,我试图通过一些更动态的方法来书写代码,具体来说就是寄希望于python的动态的优势,所有的函数都是运行时确定的,所有的类的类方法也都是运行时加载,所有实例的方法也是运行时确定。

其实这没有什么好处,尽管当初的出发点是尽量解耦,所有的方法都只需要在对应的字典中注册就好,解释器不需要知道到底运行的是什么方法。但是实践的时候,由于运行的时候,根本无法知道现在的node到底是什么类型,所以也无法从方法字典中取出相应的方法加载进去。

我的解决方法是再传入一个类,这个类持有类型说明,这个类去包装返回值,所有的操作都是在这个类上进行。

虽然看上去很可笑,但是直到处理变量计算之前都工作良好。

但是正如所说,这种方法在处理name这种情况的时候会有问题。

什么是name?a=2,a就是name。

原因是,name的时候,这个包装类实例实际是持有name类型,但是问题是,name参与计算的时候,不是name类型去参与计算,而是name中索引的那个值去参与计算。包装类可以包装name,但是无法知道name索引的那个值是什么类型。如果要解决这个问题,修正代码很恶心也很难看,所以我那时候就在考虑,到目前为止的代码是不是太过于计较trick而导致困难重重。

后面就是第二次结构修改了,以前的函数注册的方式全部用类代替,这样的话,也不需要额外的class去保留类型信息了,因为类本身就能表征不少内容。

虽然原本预计修改起来很难,因为第一次写了很久,但是事实上,意外简单。

我估摸这上面这部分很难看懂,因为很多内容实际上只有作为当事人的自己才明白,不过我这里要说的一件事是,如果一个程序或者一个模块,如果推进困难重重,甚至不得不加入各种hack代码去解决一些已有的bug,那么,请回过头去,一定有更好的方法和技巧去组织这段程序。

另外,虽然我一直认为使用函数就够了,不过,类在许多时候依然有卓越的优势,设计模式也并非一无是处。

顺便关于__init__.py,在这之前我产生过某些错觉,因为我把这玩意和类里面的__init__(self)弄混了,一厢情愿认为在这玩意里面写的代码能在import的时候自动运行,不过我的测试结果是不行。作用么,我想这玩意能更好组织一些公用的import和from…import,正如cookbook里面讨论的那样。另外,我自己比较习惯把基类写在这里面。

然后就是另一点,昨天我做了第三次结构变更。

这次的直接原因来自于这一段代码:

if not isinstance(self.left, Name):
    raise SyntaxError("can't assign to literal")

Name是我定义的一个类,而且我很确定self.left确实是Name的实例,但是这个判断条件始终判True。

于是我试着打印了一下,发现self.left的type大致是fooA.fooB.names.Name这样,Name是names.Name这样。

其实type的相等就是一个字符串的比较,这是我后来发现的。所以尽管对应的Name是同一个Name,但是包层级不对也不行。

友人A遇见过同样的问题,据他的说法,在包里面使用绝对路径导入并不是合乎规范的行为,建议我使用相对路径导入。

之前我对于相对路径导入没有任何研究,所以我继续一厢情愿地把所有类似于 fooA.fooB.name.Name 改成了 ..name.Name。

很明显,我触发了那个so上许多人问的 *Attempted relative import in non-package*异常。

具体的,我建议读一下几篇so上对于relative path import 的讨论,以及阅读pep 328

反正我总结了一下,龟叔觉得:啊哈,你想直接运行一个包里面的脚本?你怎么会有这么愚蠢的想法的?So……

总之我觉得,对python的旮旯角落知道的越多,越觉得有很多不合理->看了看别人的解释觉得合理了->还是觉得不合理的point。

恩,上次给我这个感觉的是闭包没法引用外层函数变量的那个问题,虽然不至于觉得"python的闭包是半残的" —- 某python分享会上某菜鸟分享者原话。但是总有些不是很直观的,甚至违背直觉的特性给我当头一棒……

基本上,这次的内容就到此为止,我知道写的很不清晰易懂……

我反思了一下以前的文章,大致觉得,以前的博客主要目的是分享吧,那时候,恨不得把某个语法现象的所有细枝末节全写出来。

其实现在觉得,貌似也没什么意义,大概也就是:呀,我原来研究过这个啊。

现在的话,似乎更面向自己的总结了,也就寄希望于未来的自己知道,当时自己到底为什么要这么做,为什么不这样做。

虽然依然没有意义,不过似乎更有意义?

不过也可能是我变得越来越懒:p

最近想更新自己的技术栈,我仔细考虑了一下,觉得cpp和js是个好主意。

目前有两个很希望做的项目,一个是调度器,另一个是p2p+推荐算法的小玩意。等有时间吧。

-于是我还是没有女朋友-

敬祝大家一切都好,鞠躬。

以上。