是不是觉得python3.7刚用完,3.8还没预热,为什么3.9来了真快!其实版本的迭代速度快,说明这门编程语言的生命力对我们用户来说是好事,也没有人说一定要用最新的版本。我还在用python3.6。不过新版本出来后,大家一定要体验一下,看看有哪些变化和优化。也许一个新功能可以解决你手上的大问题。1新特性1).导入异常当我们对模块进行相对引用时,可能会遇到这样的错误信息:ValueError:Attemptedrelativeimportbeyondtoplevelpackage。简单的说,这个问题是引用的模块超出了顶级目录的层次结构导致的。这个问题看不懂也没关系,因为跟python3.9的特性变化关系不大。我们只需要知道在python3.9中调整了此类错误的raise类型即可。遇到此类错误时,会提示ImportError而不是ValueError。PR如图:这个改动最大的好处就是当遇到这种问题的时候,系统会明确的告诉你是导入模块导致的。2).__file__path我们知道在python中可以使用__file__、sys.argv[0]、sys.path[0]等方法获取当前脚本的路径,但是在命令行模式下使用前两种获取的命令都是相对路径,只有第三条命令可以获取脚本的绝对路径。我们使用之前版本的python运行如下代码:importsysprint(__file__)print(sys.argv[0])print(sys.path[0])结果如下:如果使用python3.9运行结果不一样(下图),他调整了__file__和sys.argv[0],让所有的返回值都是绝对路径。3).replacerepairreplace是字符串处理中的一个常用函数,它的原型其实是这样的:str.replace(old,new[,max])其中max是一个可选参数,表示替换不超过max次。但是在以前的python版本中,如果对null值进行这种形式的替换,就会出现一点问题。例如下面的代码,它的输出仍然是空的。s=''s=s.replace('','python39',1)print(s)这个问题在python3.9已经修正,除非最大赋值是0,否则会进行正常的替换操作。此更改也适用于bytes和bytearray对象。2模块变化Python3.9并没有给我们带来新的内置模块,但是对一些模块进行了修改,我们就挑几个用得比较多的来说明。1).astast这个概念大家可能比较陌生。一般来说,我们很少有机会使用它。我们只需要知道ast对象是一个树状的语法结构即可。看下面这段代码,它的作用是把print(3+5)转成ast对象打印出来。importastfunc_def='print(3+5)'r_node=ast.parse(func_def)print(ast.dump(r_node))先用之前的版本运行,看下图的输出。我们不需要看内容。单从输出格式来看,这串代码既没有换行也没有缩进,看起来很吃力。而python3.9解决了这个问题。它在dump()方法中增加了一个参数indent,代表首行缩进字符的长度。我们对上面的代码稍作修改:importastfunc_def='print(3+5)'r_node=ast.parse(func_def)print(ast.dump(r_node,indent=2)),用python3.9运行,结果如下,这次是不是好像舒服多了?2).asyncio在python3.9中添加了一个新协程叫shutdown_default_executor()。它的作用是等待ThreadPoolExecutor中的所有线程执行完毕,并为默认线程安排关闭时间。需要注意的是调用该方法后,如果在默认线程中调用loop.run_in_executor()方法,会抛出RuntimeError。此外,如果我们使用像asyncio.run()这样的方法,shutdown_default_executor()将被自动调度。也就是说,对于asyncio的一般用户来说,python3.9的变化不会有什么实质性的影响。3).线程我们知道python子解释器不支持守护进程线程。在以前的版本中,如果一个线程是被子解释器调用的守护线程,会导致python程序崩溃。在python3.9中,遇到这种情况就会抛出RuntimeError,相当于给整个程序加了一层保护。4).pprintPython3.9对pprint的修改主要体现在增加了对types.SimpleNamespace的支持。严格来说,types.SimpleNamespace是一个简单的对象子类。为了便于理解,我们可以简单的把它看成一个数据结构。下面我来看看之前版本和python3.9的types.SimpleNamespace的数据pprint结果有什么不同。先看一段代码:importpprintfromtypesimportSimpleNamespaceK=[str(i)foriinrange(10)]L=[str(i)*20foriinrange(10)]D=dict(zip(K,L))sn=SimpleNamespace(**D)pp=pprint.PrettyPrinter(indent=4)pp.pprint(sn)其中变量sn返回的是一个命名空间,其结构类似于dict字典。再看看用之前版本的python运行脚本的输出:再看看python3.9中pprint的输出(下图),现在就知道区别在哪里了。.另外,在python3.9中修改了其他几个模块,如venv、os等,但有些修改只是针对特定的操作系统(如linux),这里就不一一列举了。3其他优化除了上面提到的一些变化之外,python3.9还优化了一些底层的东西。我认为大多数python用户将无法与这部分内容相关联。好让大家明白。1).Build和CAPI提供Py_EnterRecursiveCall()和Py_LeaveRecursiveCall()作为受限API的常规函数??。从稳定的API中删除_Py_CheckRecursionLimit。将新的公共函数PyObject_CallNoArgs()添加到CAPI,该函数调用不带参数的可调用Python对象。全局变量PyStructSequence_UnnamedField在python3.9中改为常量字符串。从Py_LIMITED_API.pyfpe.h中删除PyFPE_START_PROTECT()和PyFPE_END_PROTECT()函数。删除PyMethod_ClearFreeList()和PyCFunction_ClearFreeList()函数。2).方法调整在之前的版本中,math.factorial()函数只接受非负整数值,否则会抛出ValueError。此函数将在python3.9中弃用,任何参数都会引发TypeError。解析器模块已弃用,将在未来的Python版本中删除。修改随机模块的种子类型。从现在开始,仅支持None、int、float、str、bytes和bytearray类型。始终允许打开GzipFile文件进行读写,即使未指定模式参数也不发出警告。建议使用_tkinter.TkappType的splitlist()方法,而不是split()方法。3).被移除的模块collection.abc中的抽象基类不会暴露在常规的collection模块中。删除了sys.getcheckinterval()和sys.setcheckinterval()函数。移除threading.Thread的isAlive()方法。删除ElementTree中的getchildren()和getiterator()方法。删除旧plistlib模块的实现并删除其中的use_builtin_types参数。总结:总体来说,现在的python3.9相比3.8变化不大,大部分都是底层的东西,我们一般用户很少遇到。不过目前推出的python3.9.0a1只是第一个迭代版本,并不是正式版。后续可能还会有其他变化,但按理说变化不会太大。基于以上原因,我个人认为大家可以继续使用已有的版本来学习和工作,如果你现在的版本不是很旧的话。
