站内链接:

Python2 Or Python3

Improvement

py3 相比 py2 更加规范一些, py2 因为历史原因以及一开始的设计问题, 导致了一些问题变得复杂, 主要思想:

  • 去掉冗余的关键字, 使用轻量级的语法, 丰富的库, 不去搞特殊化, 例如print, exec, !=, <>
  • 统一化, 合并新老类, 裁减掉冗余的类结构, 例如 int 和 long 的合并
  • 统一 unicode 编码
  • 对 range, map, filter, zip 等函数, 返回迭代器, 基于上述的思想, 裁剪冗余的函数(xrange)

print

去除冗余的print关键字, 使用 print 函数进行代替.

python2

1
2
3
print u'我是python2:', 4==3
# 多行代码使用不换行以及;来达到打印一行数据的效果
print 'text:', ; print 'postfix words'

python3

1
2
3
4
5
6
7
8
9
from platform import python_version

print('Python version:', python_version())
# 不换行或者增加其他换行符
for i in range(1, 3):
print('Hello world', end='{}--'.format(i))
# 设定参数之间的分割符, 默认为空格
print('args1', 'args2', 'args3')
print('args1', 'args2', 'args3', sep=',')

division

除法在 python2 中有两种运算符: /, //, 两种类型除法:传统除法, floor除法, 其中
//在 py2/py3, floor 都是一致的, 总是取商, 省略余数.

1
2
3
4
5
6
7
8
9
# 整数
3/2 == 1
# 浮点
9/2.0 == 4.5

# 取商
3//2 == 1
9//2 == 4
9//2.0 == 4.0

在 python3 中/变为真除法, 地板除(floor)保持不变:

1
2
3
4
5
3/2 == 1.5
3/2.0 == 1.5

3//2 == 1
9//2.0 == 4.0

unicode

py3 去除了 py2 中让人感觉困惑的一点, 将 str 定义为 unicode 串, 将 byte 定义为字节串.
关于 python 的 unicode, 见unicode
的详细介绍.

Iterator

正如上面所讲述的原因, 为了统一, 裁剪冗余的函数, 对很多返回值, range, map, filter,
zip, 字典的 keys, values 都做了改动, 以迭代器方式返回, 减少性能消耗.

py3 中 xrange 被剔除, range 实现了 xrange 的功能.

1
2
3
4
num = 0
for i in range(1000000000):
num += i
print('Total value:', i)

另外, 注意 py3 中的 range 新增加__contains__方法来判断某一个整数/浮点数是否在
范围之内.
因为 py3 中 range 实现的特殊性(start, stop, step), 该函数的查找性能非常快,参考如下
range-in具体 range 中的 in/not in 实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class range(object):
def __init__(self, start, stop=None, step=1):
if stop is None:
start, stop = 0, start
self.start, self.stop, self.step = start, stop, step
if step < 0:
lo, hi = stop, start
else:
lo, hi = start, stop
self.length = ((hi - lo - 1) // abs(step)) + 1

def __contains__(self, num):
# 简单的判断, 基于整数/浮点数的特性, 快速定位
if self.step < 0:
if not (self.stop < num <= self.start):
return False
else:
if not (self.start <= num < self.stop):
return False
return (num - self.start) % self.step == 0

另外, 其他返回 iterator 的方法有:

  • zip()
  • map()
  • filter()
  • dict.keys()
  • dict.values()
  • dict.items()

如果需要返回列表, 则使用 list 对返回值进行转换即可: list({}.keys()).

1
2
3
4
5
dict1 = {'kuang':3, 'xiang': 4}
key1 = dict1.keys()
ite = key1.__iter__()
next(ite) == 'kuang'
next(ite) == 'xiang'

注意, py3 中对于迭代器删除了.next属性方法, 保留了next函数, 语法糖中都是
使用next函数来返回下一个值.

Exception

py2 中支持两种不同的异常抛出方式:

1
2
raise IOError, 'file error'
raise IOError('file error')

py3 中则仅仅支持后一种异常抛出方式:

1
raise IOError('file error')

其中对于捕获的异常, py2.7, py3 都支持使用as作为关键词来获取异常信息.

命名空间泄露

在 py2 中, for循环可能导致全局命名空间泄露, 并且不支持如下的列表推导:
[var for var in item1, item2, ...], 而使用[var for var in (item1, ...)].

1
2
3
i = 1
[i for i in range(5)]
i == 4

py3 中

1
2
3
i = 1
[i for i in range(5)]
i == 1

input

类似 1.1 节的思想, 在 py2 中inputraw_input有一定的区别, 前者要求我们输入的
任何一种类型都是 python 中已有的, 即不会帮助我们使用eval执行来获取结果.

1
2
3
4
5
6
7
8
9
10
a = input('input3:')
> input3: 123
a == 123

> input3: "kuang"
a == "kuang"

b = raw_input('input4:')
> input4: kuang
b == 'kuang'

在 py3 中则将两者合并, 都是以字符串形式读取所有的输入

python3.6

特性简介

新的语法特性:

  • PEP498: 引入新的格式化字符串, f-strings, format 的简化版
  • PEP526: 添加变量函数参数注释语法, 以便第三方基于抽象语法书进行语法检查等
  • PEP515: 增加了数字文字中下划线, 增加可读性, 并增加 format 的新格式
  • PEP525: 引入异步生成器支持, 全面放开 async/await
  • PEP530: 异步包含, 支持 list, set, dict 的列表表达式中 async for 的支持
  • PEP487: 简化类创建的自定义
  • PEP519: 添加文件系统路径协议
  • PEP529: windows 文件系统编码变为 UTF8
  • PEP520: 保留类属性定义顺序
  • PEP468: 保留关键字参数顺序, kwargs

新的命令: dict 命令改进, 相比 py3.5, 减少 20%到 25%的内存开销

PYTHONMALLOC: 新环境变量, 允许设置 python 内存分配器和安装调试 hooks

类型注解

该特性是 Python3 就提供的特性: 函数注解, 在 Python3.6 更是增加了类型注解, 其用:指定函数参数的类型, 用->指定函数的返回值类型, 但是 python 解释器不会因为这些注解而增加额外的校验, 不存在任何类型校验工作, 但这样子增加了代码的可读性, 可以让 IDE 了解类型, 提供更好的语法高亮和代码补全等操作.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 函数或方法参数注解, 以flask中_ProxyLookup为例
class _ProxyLookup:
# 元祖
__slots__ = ("bind_f", "fallback", "is_attr", "class_value", "name")

def __init__(
self,
f: t.Optional[t.Callable] = None, # 形参f, 默认值None, 类型t.Optional[t.Callable]返回的类型
fallback: t.Optional[t.Callable] = None,
class_value: t.Optional[t.Any] = None,
is_attr: bool = False, # 形参is_attr, 默认值False, 类型bool
) -> None: # 方法返回值None
# 2. 类型注解, 对变量进行注解
bind_f: t.Optional[t.Callable[["LocalProxy", t.Any], t.Callable]]

bing_f = None
self.bind = bind_f

# 2. 关于类型注解, 还可以见下面的例子
from typing import List
l: List[int] = [1, 2, 3]

引用