python深入学习(三):从py2到py3

那天晚上路师傅突然开玩笑说在学一门新语言python3,然后说python2什么2020年就不再维护,突然才意识到,python2确实已经很久没有更新了,只是一直在不断的维护修复,所以想了想,一直用2也不是办法,还是要从2转3才行。加上最近看汪神写的oj,被各种依赖关系搅得有点晕,确实没有javaweb的开发经验还是硬伤,像是spring这些框架还是得要落实的开发一点东西才会有更好的理解。跑偏了,还是回到主题了,抽空研究了一下Python的doc,读了读更新文档,大概总结了一些点,当然不够全面,因为这些只是我认为的对我比较有用的,想要更具体更详细的内容还是自己看看更新文档

个人感觉,抛开一些其它的小的用法和习惯不谈,我觉得对我个人使用python影响最大的两个改变:

  • 1、str类型和bytes类型的改动 (见下一篇文章:python深入学习(四))
  • 2、绝对路径和相对路径

第一个对于正常使用影响很大很大,我特意不在本文中涉及,单独写了另一篇文章来分析这个东西;第二个对于项目的部署几乎是毁灭性的,我在python2的项目全是相对路径引用的,emmm。还好找到了一个工具:2to3,要是没有这个工具我可能又要纠结一段时间了。 看看我找到的一些点把。

print

首先是print语句变成了print函数,几种简单的用法

Old: print "The answer is", 2*2
New: print("The answer is", 2*2)

Old: print x,           # 打印之后会额外打印一个换行
New: print(x, end=" ")  # 不打印换行打印空格

Old: print              # 打印换行
New: print()            # 打印换行

Old: print >>sys.stderr, "fatal error"
New: print("fatal error", file=sys.stderr)

Old: print (x, y)       # 打印元组
New: print((x, y))      # 打印元组

总之上面的例子都是从doc里面摘出来的,有兴趣的自己看看print这个函数就行了。

相对导入和绝对导入

不知道大家还记不记得TWCTF-2016的一道web题,给个我当时的wp把:TWCTF-2016-WEB-WriteUp-WEB-WriteUp/) 其中web压轴题目Tsurai Web的考点,如下: 比如我们运行的是main.py,然后在tmp目录下的__init__.py调用了import a,而此时的目录结构如下:

---
|-test
  |-main.py
  |-tmp
  |--|-__init__.py
  |--|-a
  |--|--|-__init__.py
  |--|-a.py

那么这个时候py2就会自动引用a文件下的__init__.py而不是a.py, 这是一个py的特性。也算是一个设计失误造成歧义了。

好的同样是上述的路径,我们做一个测试,结构图和文件内容如下:

运行结果

python_learning_3_2

因为其中python3中的引用是绝对路径,所以,在tmp/__init__.py中的import意思在当前的的PYTHONPATH,即~/test目录下的a.py或是a文件夹,必然会出错,所以要想成功引用,tmp/__init__.py的引用得改成from tmp.a import *,然后就能成功了。 这个理解起来应该不困难,所以应该会体会到在自己平时写的东西里面所需要的改变了把。

xrange->range

熟悉py2的童鞋都知道,py2中xrangerange的区别,所以我们通常选用的是xrange,但是3中删了xrange,转而修改range函数使得其和原xrange功能一样,所以这里改改习惯用range就好了,还能少打一个字母233333。

比较

这也算是一个比较重要的改动了,首先在py2中我们任意两个对象都能够比较,这一点不用赘述了。相同类型对象的比较就不多说了,数字型直接比,非数字型按照__cmp__方法定义的来比较,否则按照地址进行比较。关于不同类型比较的规则简单罗列一下好了:

  • (1) 数字类型小于非数字类型
  • (2) 非数字类型比较按照规则:dict < str < tuple
  • (3) 自定义类型按照旧式类<新式类,旧式类直接按照地址比较,

不了解旧式类和新式类的童鞋可以看看我以前一篇文章 : python深入学习(一)

上面是py2的比较,在py3中,就比较简单粗暴了,那不同类型比较就会抛出一个TypeError的异常。 说到比较就不得不说排序了。

关于比较还有一个点,py3移除了<>比较符,只能使用!=

/运算符

这个也是比较重要的点,举个实在一点的栗子,比如在py2里面我们通常写二分盲注的脚本,我们会这样

for i in xrange(100):
    start=0
    end=128
    while(start<end):
        mid=(start+end)/2
        ......
        ......

敲重点,mid=(start+end)/2,再py2中这个是整数,在py3中就不行了

#py2
>>> 1/2
0

#py3
>>> 1/2
0.5

所以不要嫌麻烦乖乖使用//整数除法把。

long类型凉凉了

py3里面没有long类型了,而是将int类型改造了下,几乎是把原来的int改造成了long,从此再也没有long类型。

确实多数时候我们并不会关系他的类型转换,但是我们以往使用的函数很多和long相关的就会凉凉了。举一个小栗子,搞加密解密的必然经常用到一个pycrypto的库,这个库里面就有很多和long类型相关的数据,比如我在做rsa的时候最常用的两个函数long_to_bytes, bytes_to_long,其中的bytes_to_long就凉凉了。因为没有long这个类型了。当然还有别的不知这一个。

旧式类的移除

同样参照我以前这篇文章:python深入学习(一)

等号功能添加

等号的左边可以用地址符接受右侧任意数量的迭代 在py2中,等号左侧参数数量要和右边迭代的数量相同 在py3中,可以如下玩法

#py2
>>> a,b,c,d,e=range(5)

#py3
>>> a,*b,c=range(5)
>>> b
[1, 2, 3]
>>> a,b,c,d,e,*f=range(5)
>>> f
[]

编码问题

在py2里面源代码以asscii默认编码,所以很多时候我们要在文件头加上类似#encoding:utf-8,这样才能在字符串里面,或是代码注释中使用中文,而在py3里面源代码以utf-8默认编码,意味什么,首先可以抛开文件头部的编码指示了,其次我们可以用中文当做变量名等等2333 ,比如

>>> 中文=123
>>> print(中文)
123

raw_input()函数移除

py2中的inputraw_input的区别就不说了,我们通常都是用raw_input,而在py3中删除了raw_input,然后其功能由input替换