"没有log的程序只能乞求其永远不要发生问题了。" -- by 我自己

这个commit我尝试继续优化代码结构,并且我想着,既然是写python,那么就想办法用点python有的特性之类的。而正当我考虑怎么让代码更python一点时候,突然程序在运行时挂了,当我正准备用著名的print夹逼调试法的时候,给了我更python形式代码的灵感,在reset到相应的commit之后,使用如下命令:

你应该能看到如下的结果:

其他的和之前没啥差别,而如果你仔细观察会发现,第一行多了一行输出。而在介绍这行输出之前,我想先说说在这个commit中我又把代码结构瞎整,哦不,是优化成什么样子。

我的出发点还是从提取函数开始,如果说第一步是把重复的部分提取为函数,那么第二步应该是让你的主要部分,也就是大部分函数main函数变得简单。当然写代码的最高境界是代码就是注释,虽然很难达到这一点,但是首先应该让程序的入口函数尽量的简单明了,这样很多时候,别人一眼就能大概知道你代码的逻辑。而不用一开始就陷入很多代码组成的复杂逻辑陷阱里面。

当然,在我的这个commit里面我还没有加上python的main函数,但是并不妨碍这个代码一看就知道入口在哪里。在具体处理每一个项目的部分,主要就是提取各个元素。而这些东西,很多只有一两行,比如拿到data sku,实际上两行代码就完成了,那么像这样的代码有没有必要提取成函数呢?好像不写成函数也能一眼就看出什么意思。我的经验是,写成函数比较好,这种可以有明确意义的写成函数不仅仅可以给其一个有意义的名字。更重要的是,我觉得写代码的时候要用发展的眼光去写,一般像这种获取某种元素的代码,很大概率会在后面的迭代过程中加入条件,或者日志记录等等。而随着这种代码不断的加入,原来的两行很有可能就变成了10行,而一个GetDataSku,任何时候都能让人知道是获取某一种元素。

按照这个逻辑,我把代码中所有获取元素的部分都提取成为了一个个函数。如果去掉我这里其实并不需要使用的dict结构,虽然在commit中并没有去掉,代码的主体部分看起来是这样的,至少我自己看起来要清晰很多,突然有一种终于TM知道自己在干嘛的感觉。

下面想说的就是这个commit中唯二能写的第二部分了,以我最大的能力来实现方便的夹逼输出调试能力。首先,这玩意儿最原始的做法是在每个函数,或者每个你怀疑出问题的地方上下分别加上一些输出,如果看到哪个输出没有被打出来,那么肯定就是这两个输出语句中的代码出问题了,或者crash了。因为我这里的函数都很小,所以我只想知道一个粗粒度的哪个函数挂了就行了,所以我就简单在每个函数的前后加上enter和exit,如果哪个函数enter了但是没有exit,说明这个函数出问题了。也就可以在这个函数里找找除了啥问题就行了,虽然我的函数不多,但是每个函数加个输入输出,对于我这种懒人还是太麻烦了。

这个时候我想到了python里面的一个语法糖,decorator,装饰器。这个概念并不是python独有的,闭包的概念更是几乎现代语言所通用的。最简单的理解就是当你使用装饰器的时候,相当于利用装饰器这个函数去调用另外的函数,这样你就可在调用函数前后做一些工作。当然,打一个log是最简单的那种。

python装饰器的语法很简单,只要在你想装饰的函数之前写上@加上装饰器的名字就完成了。

而这个所谓的装饰器名称,其实就是一个函数的名称,其定义方法和定义普通的函数并没有太大区别,但是一般需要传递一个func参数,如果用c++的术语描述,就是需要传递一个函数指针,这样你才能在这个装饰器函数中调用实际的函数。

这个函数和普通函数可能唯一有点不同的是,他的返回值一定是一个函数,不然如何能完成对真正的函数,给解释器一个合理的交代?而这一个整体,就是传说中的闭包。而对于闭包比较学术的解释是这样的:

闭包是由函数和与其相关的引用环境组合而成的实体。

非常拗口并且不知所云,但是如果用通俗一点话解释的话,我觉得闭包主要解决了两个问题:

  • 如何创建一个单位,或者一个实体,这个实体构成了一个特定的环境,而这个环境可以多次被实例化,并且执行。
  • 如何解决在离开某些代码块,一些变量还可以存在。

闭包的概念很复杂,也不是几句话就能说的很明白的,如果有兴趣并且英语还挺好的,我其实挺推荐这篇文章的。简单的说,闭包就是提供了一个外部函数和内部函数的桥梁。比如在我们的代码中,我们使用闭包来将外部函数(要调用的函数)和输出log链接起来。那么整体上一个闭包看起来是这个样子的,当然最外面一句只是规定了下log的输出格式:

函数里面再定义一个内部函数是python装饰器函数最直观的特点之一,而这个函数的参数也挺别致,只要你用过python其实就明白,这样写,其实就表示这个函数能够接受一切形式传进来的参数。而再多看几行,似乎这个参数最终是传递的实际调用的那个函数的参数,闭包就是利用了这样神奇的特性来实现的,这些变量既不是全局变量,也不是局部变量,而是被称之为自由变量的东西。正是由于这样的特性,闭包才能被实现。在被调用的函数前后,加入了log,并且利用了python方便的方式取得了函数的名称。你可以把这个装饰到任一函数之上,就可以方便的在需要的函数的执行和离开的时候打印出夹逼代码了。当然,我的这个log有点简陋,所以我为了看起来能过的去,在下一个commit中,稍微复杂了一点这个打印log的功能。

results matching ""

    No results matching ""