> For the complete documentation index, see [llms.txt](https://toska.gitbook.io/echoshell/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://toska.gitbook.io/echoshell/automation/python/ji-chu/py2-vs-py3.md).

# py2 vs py3

#### print

在进行程序调试时用得最多的语句可能就是 `print`，在 Python 2 中，print 是一条语句，而 Python3 中作为函数存在。有人可能就有疑问了，我在 Python2 中明明也看到当函数使用：

```
# py2
print("hello")  # 等价 print  ("hello")

#py3
print("hello")
```

然而，你看到的只是表象，那么上面两个表达式有什么区别？从输出结果来看是一样的，但本质上，前者是把 `("hello")`当作一个整体，而后者 `print()`是个函数，接收字符串作为参数。

```
# py2
>>> print("hello", "world")
('hello', 'world')

# py3
>>> print("hello", "world")
hello world
```

这个例子更明显了，在 py2 中，print语句后面接的是一个元组对象，而在 py3 中，print 函数可以接收多个位置参数。如果希望在 Python2 中 把 print 当函数使用，那么可以导入 future 模块 中的 print\_function

```
# py2
>>> print("hello", "world")
('hello', 'world')
>>> 
>>> from __future__ import print_function
>>> print("hello", "world")
hello world
```

#### 编码

Python2 的默认编码是 asscii，这也是导致 Python2 中经常遇到编码问题的原因之一，至于是为什么会使用 asscii 作为默认编码，原因在于 Python这门语言出来的时候还没出现 Unicode。Python 3 默认采用了 UTF-8 作为默认编码，因此你不再需要在文件顶部写 `# coding=utf-8` 了。

```
# py2
>>> sys.getdefaultencoding()
'ascii'

# py3
>>> sys.getdefaultencoding()
'utf-8'
```

网上不少文章说通过修改默认编码格式来解决 Python2 的编码问题，其实这是个大坑，不要这么干。

#### 字符串

字符串是最大的变化之一，这个变化使得编码问题降到了最低可能。在 Python2 中，字符串有两个类型，一个是 unicode，一个是 str，前者表示文本字符串，后者表示字节序列，不过两者并没有明显的界限，开发者也感觉很混乱，不明白编码错误的原因，不过在 Python3 中两者做了严格区分，分别用 str 表示字符串，byte 表示字节序列，任何需要写入文本或者网络传输的数据都只接收字节序列，这就从源头上阻止了编码错误的问题。

| py2     | py3  | 表现 | 转换     |
| ------- | ---- | -- | ------ |
| str     | byte | 字节 | encode |
| unicode | str  | 字符 | decode |

#### True和False

True 和 False 在 Python2 中是两个全局变量（名字），在数值上分别对应 1 和 0，既然是变量，那么他们就可以指向其它对象，例如：

```
# py2
>>> True = False
>>> True
False
>>> True is False
True
>>> False = "x"
>>> False
'x'
>>> if False:
...     print("?")
... 
?
```

显然，上面的代码违背了 Python 的设计哲学 *Explicit is better than implicit.*。而 Python3 修正了这个缺陷，True 和 False 变为两个关键字，永远指向两个固定的对象，不允许再被重新赋值。

```
# py3
>>> True = 1
  File "<stdin>", line 1
SyntaxError: can't assign to keyword
```

#### 迭代器

在 Python2 中很多返回列表对象的内置函数和方法在 Python 3 都改成了返回类似于迭代器的对象，因为迭代器的惰性加载特性使得操作大数据更有效率。Python2 中的 range 和 xrange 函数合并成了 range，如果同时兼容2和3，可以这样：

```
try:
    range = xrange
except:
    pass
```

另外，字典对象的 dict.keys()、dict.values() 方法都不再返回列表，而是以一个类似迭代器的 "view" 对象返回。高阶函数 map、filter、zip 返回的也都不是列表对象了。Python2的迭代器必须实现 `next` 方法，而 Python3 改成了 `__next__`

#### nonlocal

我们都知道在Python2中可以在函数里面可以用关键字 `global` 声明某个变量为全局变量，但是在嵌套函数中，想要给一个变量声明为非局部变量是没法实现的，在Pyhon3，新增了关键字 `nonlcoal`，使得非局部变量成为可能。

```
def func():
    c = 1
    def foo():
        c = 12
    foo()
    print(c)
func()    #1
```

可以对比上面两段代码的输出结果

```
def func():
    c = 1
    def foo():
        nonlocal c
        c = 12
    foo()
    print(c)
func()   # 12
```

其实很多内建模块也做了大量调整，Python3 中的模块组织更加清晰，类更加先进，还引入了异步IO，这次先写这么多，下次再继续。<br>

参考： <https://foofish.net/python2_python3.html>
