Skip to main content

3.7【2018-6】

🌟新增

官方地址

1、数据容器 dataclass

注意:

当然在 Python 3.6 版本也可以使用这个功能,不过需要安装 dataclasses 这个库,使用 pip install dataclasses 命令就可以轻松安装, Github地址: dataclass (在 Python 3.7 版本中 dataclasses 已经作为一个标准库存在了)

dataclass实际上也是普通的python对象,只不过dataclass帮我们将 __init__()、 __repr__()和__eq__()封装,更简洁的提供给我们使用。

基础使用

from dataclasses import 
dataclass,
asdict,
field,
make_dataclass

几个主要的模块

  • dataclass - 装饰器
  • make_dataclass
  • asdict - 以字典形式
  • field - 字段定义
    • 语法: field(default="默认值", default_factory="默认类型")

解决了什么问题

1、数据结构复杂后,难以维护

dataclass 可以解决复杂数据结构难以维护的问题和减轻开发压力

  • 可以当作一个类来使用即可
import typing
from dataclasses import dataclass, asdict, field

@dataclass
class User:
name: str = field(default_factory=str)
age: int = field(default=18)

# 为数据容器提供一个方法
def say_hello(self):
print(f"{self.name}: hello")

# 实例化
u = User(name="shadow", age=20)
print(u)
print(u.name)
print(u.age)
print(u.say_hello())
print(asdict(u))

# 输出
>> User(name='shadow', age=20)
>> shadow
>> 20
>> shadow: hello
>> {'name': 'shadow', 'age': 20}

2、定义数据对象更少的代码量

python3.7 的dataclass新特性大大简化了定义类对象的代码量,代码简洁明晰。通过使用@dataclass装饰器来修饰类的设计,例如

# 传统写法
class Persion:
def __init__(self, age:int, name:str):
self.age = age
self.name = name

如果我们创建一个类只是用来存放数据,每次这样写会显得非常繁琐和多余,所以dataclass就解决了这个痛点,对于仅仅用来保存数据的类,可以简化非常多的步骤

# 使用 @dataclass写法
from dataclasses import dataclass

@dataclass
class Person:
age: int = 18
name: str = "no_name"

结果:

#生成实例
p = Person(age=18, name='capsion')
print(p.age)
print(p.name)
print(p)

3、自定义复杂的数据类型标注

import typing
from dataclasses import dataclass, asdict, field

@dataclass
class BasicUser:
id: int = field(default_factory=int)

@dataclass
class Job:
position: str = field(default_factory=str)

@dataclass
class User(BasicUser):
name: str = field(default_factory=str)
age: int = field(default=18)

# 使用自己定义的类型来标注
job: Job = field(default_factory=Job)


u = User(name="shadow", age=18, job=Job(position='ops'))
print(u)
print(asdict(u))

# 输出
>>
>> User(id=0, name='shadow', age=18, job=Job(position='ops'))
>> {'id': 0, 'name': 'shadow', 'age': 18, 'job': {'position': 'ops'}}
  • 这里可以看到User在实例化的时候并未传入id, 因此它会使用我们提供的工厂类int进行实例化所以id=0

4、列表导出

import typing
from dataclasses import dataclass, asdict, field

@dataclass
class User():
name: str = field(default_factory=str)
age: int = field(default=18)
# job: Job = field(default_factory=Job)


@dataclass
class Group:
# 定义了一个ops_group列表,列表里面的属性标记为User类型
ops_group: typing.List[User] = field(default_factory=typing.List)

u = User(name="shadow", age=20)
u1 = User(**{"name": "shadow1"})

g = Group(ops_group=[u, u1])
g1 = Group(**{"ops_group": [{'name': 'shadow', 'age': 18}]})

print(g.ops_group)
print(asdict(g))

print(g1)
print(asdict(g1))

# 输出
>> Group(ops_group=[User(name='shadow', age=20), User(name='shadow1', age=18)])
>> {'ops_group': [{'name': 'shadow', 'age': 20}, {'name': 'shadow', 'age': 18}]}
>>
>> Group(ops_group=[{'name': 'shadow', 'age': 18}])
>> {'ops_group': [{'name': 'shadow', 'age': 18}]}

  • 乍一看好像没什么毛病能正常解析列表也能反解析出dict,可以留意一下g1的输出,ops_group列表内的User对象并没有被解析出来,仅仅只给了ops_group一个列表;

✴优化

0、模块优化

模块优化内容
argparse在大多数的 unix 命令中,parse_intermixed_args() 能让用户在命令行里混用选项和位置参数,它支持大部分而非全部的 argparse 功能。
binasciib2a_uu() 函数现在能接受一个可选的 backtick 关键字参数,当它的值为 true 时,所有的“0”都将被替换为 ''` 而非空格。
calendarHTMLCalendar类具有新的类属性,它能在生成的 HTML 日历中很方便地自定义 CSS 类。
cgiparse_multipart() 作为 FieldStorage 会返回同样的结果:对于非文件字段,与键相关联的值是一个字符串列表,而非字节。
contextlib已添加 contextlib.asynccontextmanager()
dis函数现在可以反汇编嵌套代码对象(代码解析,生成器表达式和嵌套函数,以及用于构建嵌套类的代码)
distutilsREADME.rst 现已包含在 distutils 的标准自述文件列表中,进而它也分别包含在各源码中。
http.serverSimpleHTTPRequestHandler 支持 HTTP If-Modified-Since 头文件。如果在头文件指定的时间之后,目标文件未被修改,则服务器返回 304 响应状态码。

SimpleHTTPRequestHandler 中添加 directory 参数,在命令行的 server 模块中添加 --directory。有了这个参数,服务器将会运行在指定目录下,默认使用当前工作目录。
localelocale 模块的 format_string() 方法中添加了另一个参数 monetary 。如果 monetary 的值为 true,会转换为使用货币千位分隔符和分组字符串。
math新的 remainder() 函数实现了 IEEE 754-style 的取余操作。
os增加了对 fwalk() 中 bytes 路径的支持。
增加了对 fwalk()bytes 路径的支持。
pdbset_trace() 现在需要一个可选的 header 强制关键字参数。如果已给出,它将会在调试开始前打印至控制台。
stringstring.Template现在可以分别为花括号占位符和非花括号占位符选择性地修改正则表达式模式。
unittest.mocksentinel 属性现在会保留自己的同一性,当它们被 copiedpickled 时。
xmlrpc.serverxmlrpc.server.SimpleXMLRPCDispatcherregister_function() 及其子类能被用作装饰器。
unicodedata内部的 unicodedata 数据库已升级,能够使用 Unicode 10。
urllib.parseurllib.parse.quote() 已经从 RFC 2396 升级至 RFC 3986,将 ~ 添加到默认情况下从不引用的字符集中。
uu函数 encode() 现在能接受一个可选的关键字参数 backtick ,当它的值为 true 时,“0”会被 ''` 替代而非空格。
zipapp函数 zipapp.create_archive() 现在能接受一个可选的参数 filter,来允许用户选择哪些文件应该被包含在存档中。

其他优化

  • 当在一字符串内查找某些特殊的 Unicode 字符(如乌克兰大写字母 “Є”)时,将会比查找其他字符慢25倍,但现在最差情况下也只慢了3倍。(由 Serhiy Storchaka 参与贡献的 bpo-24821。)

  • 标准C语言库的快速执行现在能用于 math 模块内的 erf()erfc() 函数。(由 Serhiy Storchaka 参与贡献的 bpo-26121。)

  • 由于使用了 os.scandir() 函数,os.fwalk() 函数的效率已经提升了2倍。 (由 Serhiy Storchaka 参与贡献的 bpo-25996。)

  • 优化了对于大小写忽略的匹配及对于 regular expressions 的查找。 对一些字符的查找速度现在能提升至原来的20倍。(由 Serhiy Storchaka 参与贡献的 bpo-30285。)

  • 在较重负荷下,selectors.EpollSelector.modify()selectors.PollSelector.modify()selectors.DevpollSelector.modify() 将比原来快10%左右。(由 Giampaolo Rodola’ 参与贡献的 bpo-30014。)

1、遗留的C语言本地化编码自动强制转换问题

Python 3 系列版本中,确定一个合理的默认策略来处理当前位于非 Windows 平台上默认C语言本地化编码隐式采用的“7位 ASCII”,是个永不停歇的挑战。

PEP 538 更新了默认的解释器命令行界面,从而能自动地将本地化编码强制转换为一种可用的且基于 UTF-8的编码,它就是文档里所描述的新环境变量 PYTHONCOERCECLOCALE。用这种方式自动设置 LC_CTYPE 意味着核心解释器和关于本地化识别的C语言扩展(如 readline)将会采用 UTF-8 作为默认的文本编码,而不是 ASCII。

PEP 11 中有关平台支持的定义也已经更新,限制了对于全文处理的支持,变为适当的基于非 ASCII 的本地化编码配置。

作为变化的一部分,当使用任一强制转换的已定义目标编码(当前为 C.UTF-8C.utf8UTF-8),stdinstdout 的默认错误处理器现在为 surrogateescape(而不是 strict);而 stderr 的默认错误处理器仍然是 backslashreplace,与语言环境无关。

默认的本地化编码强制转换是隐式的,但是为了能帮助调试潜在的与本地化相关的集成问题,可以通过设置 PYTHONCOERCECLOCALE=warn 来请求直接用 stderr 发出明确的警告。当核心解释器初始化时,如果遗留的C语言本地化编码仍是活动状态,那么该设置会导致 Python 运行时发出警告。

PEP 538 —— 把遗留的C语言本地化编码强制转换为基于 UTF-8 的编码。

2、函数的参数数量增加

现在传递给某个函数的参数( argument )可以超过255个,且一个函数的形参( parameter )可以超过255个。(由 Serhiy Storchaka 参与贡献的 bpo-12844bpo-18896。)

3、bytes.fromhex和bytearray.fromhex

bytes.fromhex()bytearray.fromhex() 现在将忽略所有的 ASCII 空白符,而不止空格。(由 Robert Xiao 参与贡献的 bpo-28927。)

4、from ... import ...错误提示更准确

现在当 from ... import ... 失败的时候,ImportError 会展示模块名及模块 __file__ 路径。(由 Matthias Bussonnier 参与贡献的 bpo-29546。)

5、imports的循环绑定

现在已支持将包含绝对 imports 的循环 imports 通过名称绑定到一个子模块上。(由 Serhiy Storchaka 参与贡献的 bpo-30024。)

6、object.__format__(x,'')等价于str(x)

现在,object.__format__(x,'') 等价于 str(x) ,而不是 format(str(self),'')。(由 Serhiy Storchaka 参与贡献的 bpo-28974。)

7、CPython 字节码的更改

添加了两个新的操作码:LOAD_METHODCALL_METHOD,从而避免为了方法调用的绑定方法对象的实例化,这将导致方法调用的速度提升20%。(由 Yury Selivanov 及 INADA Naoki 参与贡献的 bpo-26110。)

🗑弃用

  • 在使用 re.sub() 的替换模板中,由 '\' 及一个 ASCII 字母组成的未知转义符已在 Python 3.5 中被弃用,现在使用将会报错。

  • 移除了 tarfile.TarFile.add() 中的实参 exclude 。它已在 Python 2.7 和 3.2 版本被弃用,取而代之的是使用实参 filter

- ntpath 模块中的 splitunc() 函数在 Python 3.1 被弃用,现在已被移除。使用 splitdrive() 函数来替代。

  • collections.namedtuple() 不再支持 verbose 参数和 _source 属性,该属性用于显示为已命名元组类所生成的源码。这是用来提升类创建速度的优化设计的一部分。(由 Jelle Zijlstra 贡献并由 INADA Naoki,Serhiy Storchaka,和 Raymond Hettinger 进一步完善的 bpo-28638。)

  • 函数 bool()float()list()tuple() 不再使用关键字参数。int() 的第一个参数现在只能作为位置参数传递。

  • 移除了先前在 Python 2.4 版本已被弃用的在 plistlib 模块中的类 PlistDict_InternalDict。函数 readPlist()readPlistFromBytes() 返回结果中的 dict 类型值现在就是标准的 dict 类型。你再也不能使用属性访问来访问到这些字典里的项。

  • 如果未设置 Py_LIMITED_API ,或其被设置为从 0x030504000x03060000 (不含)的值或不小于 0x03060100 的值,将弃用函数 PySlice_GetIndicesEx() 并用宏将其替代。(由 Serhiy Storchaka 参与贡献的 bpo-27867。)

  • format_string() 来替代 locale 模块中被弃用的 format()。(由 Garvit 参与贡献的 bpo-10379。)

  • 方法 MetaPathFinder.find_module()(由 MetaPathFinder.find_spec() 替代)和方法 PathEntryFinder.find_loader()(由 PathEntryFinder.find_spec() 替代)都已在 Python 3.4 被弃用,且现在会发出 DeprecationWarning的警告。(由 Matthias Bussonnier 参与贡献的 bpo-29576。)

  • gettext 中通过使用非整型值来筛选复数形式的值已被弃用,它不会再起作用。(由 Serhiy Storchaka 参与贡献的 bpo-28692。)

  • macpath 模块已被弃用,且它将会在 Python 3.8 版本中被移除。

💥破坏性更新

1、pkgutil.walk_packages()

如果 path 是一个字符串,pkgutil.walk_packages() 现在会引起 ValueError 报错,之前会返回一个空列表。(由 Sanyam Khurana 参与贡献的 bpo-24744。)

2、string.Formatter.format()

string.Formatter.format() 的格式化字符串参数现在是 positional-only,将它作为关键字参数传递已在 Python 3.5 时被弃用。(由 Serhiy Storchaka 参与贡献的 bpo-29193。)

3、http.cookies.Morsel

http.cookies.Morsel 类的属性 keyvaluecoded_value 现在是只读的,将值分配给它们已经在 Python 3.5 中被弃用了,需要使用 set() 方法对它们进行设置。(由 Serhiy Storchaka 参与贡献的 bpo-29192。)

4、ModuleFunctionDefAsyncFunctionDef

ModuleFunctionDefAsyncFunctionDefClassDef AST 节点现在新增了一个 docstring 字段,它们自身的首次声明不再被当做是一个 docstring。类和模块的代码对象 co_firstlinenoco_lnotab 会因这个更改而受到影响。(由 INADA Naoki and Eugene Toder 参与贡献的 bpo-29463。)

5、os.makedirs()

os.makedirs() 的参数 mode 不再影响新建的中级目录的文件权限位,要想设置它们的文件权限位,你可以在调用 makedirs() 之前设置 umask。(由 Serhiy Storchaka 参与贡献的 bpo-19930。)

6、struct.Struct.format

现在 struct.Struct.format 的类型是 str 而非 bytes。(由 Victor Stinner 参与贡献的 bpo-21071。)

7、socket.fromshare()

由于 socket 模块的内部更改,你将无法在旧版本 Python 中通过 socket.fromshare() 创建一个 share()-ed(共享的)接口。

8、datetime.timedeltarepr

datetime.timedeltarepr 已变为在输出中包含关键字参数。(由 Utkarsh Upadhyay 参与贡献的 bpo-30302。)