Python再入门

会用一门语言写代码并不能说是掌握了这门语言,尤其是入门容易的语言,掌握起来更困难。你说你会用汇编写程序,我可以承认你掌握了汇编语言,而你说会用Python写程序,十有八九真的只是会写而已。

有基础的哥们,Python能在3分钟内入门,其他解释性语言也是如此,不用花太多时间,就能说我会了,只要能让我查google。我从大一(2011)开始接触Python,几乎每个月都在学新的内容。当然,我新学的内容不是Pythonic。


Python基础库

我很久以前买了一本很厚的《Python标准库》,结果才看了不到100页。最近,我才真正认识到标准库的作用。此处,我不会考虑Python 2,我只会Python 3。

unicodedata

unicodedata对我这样的多语言工作者还是比较有用的,目前这个库只提供了各个unicode字符所属的类别,如’我’是符号类别(‘Lo’),’1’是数字类别(‘Nd’),这样我就不用翻wikipedia了。不过,这个库也没有完全满足我的需求,经常需要查阅unicode各个块(unicode_block)的信息。

collections

提供了除基础容器list,tuple,dict,set以外的容器,我比较常用的是namedtuple和defaultdict。defaultdict就是在赋值的时候不用手动初始化,考虑简单的计数问题(仅仅是实例,可以用counter)。

复杂一点的,如针对各个字符串统计各字符数的defaultdict,也就是defaultdict的defaultdict。

array

与list类似,不过array的数据存储更加原生,而且array中的数据类型得一致,就像C/C++一样。看例子就明白了。

此处我反正是搞不懂为啥a只用87624个bytes,这乘法不对啊。40064就容易理解多利,10000个整数,每个4 bytes,加上数据结构64 bytes,这个空间直接省了1半。当然也可以用numpy。

linecache

随机读取文件行,小文件可以,大文件直接内存爆炸。

timeit

规范的测试几行代码速度的工具,使用也很方便。

operator

我曾经一直不理解operator的用处,跟内置的运算符重复,实在没有,也可以使用lambda。后来我搜索了一下,stackoverflow,stackoverflow2,给了我一点启示。主要出于速度、代码可读性、以及picklable考虑。关于速度可以简单测试如下,

itertools

与operator一样,属于函数式编程模块。借鉴了Haskell等语言的思想,实现了大量高效、内存友好的迭代工具,与operator相辅相成。官方介绍中也提供了很多例子。我用得最多的居然是chain.from_iterable(),我觉得我得改。takewhile这些都很不错。

functools

与上面两个一样,属于函数式编程模块。其中的lru_cache是比较典型的操作,能很好的解释functools。另外wraps也是常用的,其他几个我还没有使用过。

typing

使用type hints可以帮助我们在编码时就发现bug,当然借助的是ide的提示。mypy也可以进行代码检查,可以告知哪里类型有问题,可以及时发现处理。

其他

其他很多库,如heapq,bisect,re,threading,multiprocessing,profile,pdb,json等都是非常常用好用的库。如果能灵活使用这些库,必定能提供编码效率。此处效率包括编程速度和运行速度。估计我也就掌握了1/10左右。


每个半年回过头看自己写的老代码,总感觉非常羞耻,想推倒重来。我觉得这是好事,说明人还在进步学习。希望还能保持这个速度。

链接

  1. Python 3基础库

 

验证码识别

因为看到学校的饭卡网站坑爹,而我的技术又不到家黑不了这个网站,而他只有6位密码,所以想暴力试试(捉弄一下小伙伴)。因为有验证码的关系,暴力的期望时间大概为14个小时。完全可以接受啊。但首先是要搞定这验证码啊!话说这事很久以前我就想做了,因为之前就听说过tesseract这吊炸玩意。所以这里讲的不是如何去写个神经网络来训练,也不是opencv来解决。如果感兴趣的话可以参考最下面的链接。


初步尝试

怎么安装我就不说了,参考主页。我要使用python,网上也有封装好的利用tesseract的库,但是我死活搞不定所以索性就不用了。毕竟只要执行一个命令就行了。先来说我要破解的验证码长什么样,如下图(原验证码),毕竟需求不同。但是原理大同小异。然后输入 tesseract captcha.jpg 2 -psm 6 digits 。这命令含义就是假定是一块数据(-psm 6),而且全是数字(digits),输出到2.txt。这里的digits是配置文件。在/usr/share/tessdata/configs/digits,内容只有一行: tessedit_char_whitelist 0123456789-.  但是2.txt里居然什么也没有。网上查了查,好像是因为DPI不够,这不是坑爹吗。确实图片比较小。根据他的ImproveQuqlity,我发现我需要做两件事。一是去掉边框,二是去掉噪点。

手动去噪

用GIMP对原图来了一发。效果如下图(GIMP处理后)。同样的命令,结果就出来了。但是好像哪里不对。我这是要暴力登录啊,这样处理图片的话还不如手动输入验证码。所以还得自己写。

Python去噪

很简单的思路,就是把边框去掉,然后把单独的黑点去掉。这个已经差不多了,要考虑4这个奇葩的数字,还有这可以的dpi。我走了不少弯路,其实质的提高是对图片分割。而且不能分开后一张张算,要在原图中分割。经过观察,这些数字的位置基本不变,在像素点1,10,19,28的位置加一条白线即可。效果如下(python处理)。这个程序的准确率居然是精准的2/3。。可以接受。程序代码如下,都没有100行,很简单啊。我已经破了两个小伙伴的密码了。很可惜,都是身份证后六位,没改过不好玩。

captcha18671867(2)erase_1867


训练数据

所以说写博客还是很重要的。写的时候,我发现tesseract还自带训练。但是用在验证码处理就不太合适了。这是为没有特定字符的文字训练的,比如中文。而且感觉还比较复杂,不过有GUI工具。我就不去深入研究了。


链接

  1. Simple CAPTCHA solver in python
  2. Solving CAPTCHA with OCR
  3. OCR of Hand-written Data using kNN,  Simple Digit Recognition OCR in OpenCV-Python
  4. tesseract-ocr parameters
  5. python-tesseract, pytesser

Python: function

      Python基本的内容已经回顾完了。这次的function真的是让我好好消化了一下。特别是Python中的闭包(Closure),由于之前没有实际用过,不是很能切身体会其用处。我目前只能理解到enclosing function这个层面。

function coding:

      Python最简单的表示函数的方法是 def ,之后的code block就是一个函数体。当然还有lambda函数等等。Python不仅有一般的返回方式,比如 return ,还支持 yield (比较高级,到generator时再展开)。这两者的主要区别是yield记住了函数处理的位置。比如读一个大文件,使用yield就能一段段返回,这也是Python内置open函数的标准做法。

      Python中还有compile能生成函数。最酷炫的定义函数的方法在下文提到。原文见stackoverflow.

      Python中所有变量都是对象。函数也不例外。最简单的证明就是

      函数这个变量不是像C一样编译时就确定的。是运行时动态确定的。这点也很容易理解,毕竟Python是脚本语言。

function object:

      既然函数是个对象,那么这里面装的是什么?自然的好奇,一下子将我带入高级领域了。接触了dis,code,inspect等等好多底层的,一下子反应不过来。先看最相关code。进行测试:

      输出为:

      code这个对象就是function的核心。我这么认为。因为这包含了函数的机器码。Python内置了反编译dis模块。看看酷炫的函数生成方式和dis模块的相应作用。再次声明这代码我目前没能力写出,理解也好半天,娱乐一下,原文见大神。输出见不看了,代码在Python 3可直接运行看输出。

nested function:

      Python的作用是根据LEGB来的。从Local->enclosing->global->buildin。最难以理解的是enclosing。而且Python2和3还有区别。Python3多了nonlocal,一下子提升了nested function的实用性,或者说是提供了便利性。先看代码例子。

      nested function的主要应用场景就是上面所示。生成一个附带上下文信息的独立函数。比如F,G各自都是独立的带有信息state。这貌似就是class。但实际上还是有区别的。首先写法就不一样。然后结构也不一样。然后据说效率也不一样。当然同样的功能class一定能实现。

      回到LEGB。如上面的例子。E就是代码nested function到最外层的函数为止的作用域,不包括最外层的函数外面的。在Python 2只能在nested function里引用E中变量,即read only。Python 3使用nonlocal后就能表明这个变量要在nested function里改变。虽然Python 2能用一些技巧实现同样的事,但总归不自然。

      函数还有部分内容,内容太多,分开写。

链接:

  1. python code object
  2. Exploring Python Code Object