介绍
Python 3.8 发布于 2019 年 10 月 14 日,在很多方面都进行了提升,特别是加入了海象运算符,用习惯了还是挺方便的,大家快来尝鲜吧。
知识点
- 海象运算符
- 字典反转
- f-string
- 仅限位置形参
Python3.8安装
官方网址:
Python Release Python 3.8.1 | Python.org
根据自己系统选择所需下载版本,我是Windows x86系统选的是这个图形化的安装自动安装,绝大多数情况下,特别是学习阶段,32 位还是 64 位没有区别。今后我们编写的所有 Python 代码,也不会区分是多少位。
大家现在所用的 Python 是 C 语言实现的 CPython,它可以直接使用 C 语言编写的模块。这些 C 语言模块针对不同位数的 Python 编译出来的结果只能用在特定的版本上。
大多数情况下,这些模块会同时提供针对不同位数的版本,直接使用 pip install 的时候会自动匹配。只是有些时候手动下载安装包的时候,需要注意版本要匹配一致。
开始安装
可以选择Install Now(立即安装),也可以选择Customize installation(自定义安装),想偷懒的可以直接选择Install Now
自定义安装有 2 个对话框选择,
第一个默认都是勾选上的,每个选项是啥意思介绍如下:
- Documentation 离线的 .chm 格式文档,必须保留。英文还 OK 的小伙伴可以直接看这份文档,比所有书都靠谱。看英文有压力的,平时随时查查标准库模块用法什么的是极好的。
- pip Python 包下载工具,必须保留。(想找虐的随意)
- tcl/tk and IDLE ,说来话长,保留就对了。
- Python test suite,这个可以没有,当然留下来也没关系。
- py launcher,前面介绍过了。这里额外注意的是 for all user 选项,可以选择是否对所有用户安装。如果对所有用户安装,则需要 administrator 的权限。
第 2 个对话框是高级选项:
- Install for all user,是否对所有人安装,如果是,需要 administrator 的权限,并且安装路径会有所不同。
- 关联文件到 Python,这个保持原样即可。它就是把 .py 文件和 python 程序关联起来,这样双击 .py 文件的时候,自动就用 python 去执行了。
- 创建快捷方式,保持原样即可。
- 添加 Python 到环境变量,第 2 次修改的机会
- 预编译标准库,一次性的把标准库的 .py 都预编译成 .pyc,没什么必要,会多花费安装时间,不选
- 两个 download debug xxx ,不知道哪里会用到,都不选
最下面是指定安装路径,个人意见,保持默认即可。如果取消勾选为所有人安装,则默认安装的路径会比较深,这个看上去有点不舒服,但是绝大多数情况下我们都不会直接造访该目录,所以不会有什么影响。
“ 我个人的推荐操作是 不选择对所有用户安装,这样如果想使用多个用户,每个用户有自己选择的自由。“
安装后的基本测试
安装完成后,新打开一个命令行窗口,win + r,然后输入 cmd(ps:“ 注意,必须重新打开,在安装 Python 前已打开的命令行不会自动更新环境变量。”)
依次执行下面的命令:
# 注意,-0 后面是数字 0,不是字母 o
py -0
或者
py --list
这就是调用 Python 启动器,它显示出系统中已安装的 Python 版本。
python --version
这是直接调用 Python 解释器,打印出它的版本。
pip --version
为什么要测试这 3 个命令,因为它们分别安装在了不同的位置,都工作正常了,就证明安装没有问题了。
想要了解更多细节,我们来查看 PATH
环境变量。
安装后的 PATH
变化
因为没有选择为所有用户安装,所以环境变量看当前用户的:
“ 安装时的选择不同,这里环境变量出现的位置也会有所不同”
上面 3 条就是安装后自动添加的。
“ 注意,如果 launcher 没有取消勾选 for all user,则会默认安装在系统目录下,就不需要添加到 PATH,这里就只有 2 条新增。
安装目录详情
先来看 C:\Users\Davy\AppData\Local\Programs\Python\Python38
,也就是 Python 的安装路径,它是包含 python.exe
的目录。
其它目录的作用:
- DLLs,静态链接库,里面是一些 .dll 和 .pyd 文件,一般不会直接和这个目录打交道
- Doc,文档,里面就是一个 python381.chm,快捷方式里包含了该文档路径,所以平常不会直接访问
- include,头文件,基本上不会用到
- Lib,这个目录最最重要,几乎所有的标准库源码都在这里面了,大部分平常都不会去动它们,除了其中一个子目录:
- site-packages 后续安装的第三方模块和包都会出现在这里,所以偶尔出现问题,我们会造访这里。
- libs,几乎不会直接用到,注意和 Lib 区分开。(因为 Windows 系统路径不区分大小写,所以 Lib 实际会展示成 lib )
- Scripts,后续安装的第三方包如果提供了命令,可执行文件就会出现在这里。例如 pip.exe 就是在此目录下,而 Lib 目录下保存的是 pip 的源码。
- tcl,仍然是说来话长,略过
- Tools,自带的一些 Python 脚本,包括一些 demo,其中有些可以作为学习参考。
最后看 launcher
的目录,它要管理所有的 Python 版本,所以它是超脱在外的,安装在了 Python38 的上级目录中。
启动菜单详情
安装 Python 后在开始菜单会多出来 4 个快捷方式,一般很少用,做一个简单的介绍:
- IDLE (Python 3.8 64-bit),用来启动 IDLE ,以后再详细介绍它。
- Python 3.8 Module Docs (64-bit),点击会自动启动一个本地 web 服务,然后自动打开包含模块文档的网页,样式非常古老,而且其中的内容都包含在下面的文档文件中了,所以基本没人会用这个。
- Python 3.8 Manuals (64-bit),点击打开文档
- Python 3.8 (64-bit),点击用来启动 Python 解释器。用这种方法启动解释器,退出后就整个黑窗口都消失了,打印的信息也都看不到了,所以我们一般是先启动命令行,再从命令行内启动 Python,这样即使解释器退出了,也能看到刚才程序执行的结果。
海象运算符(赋值表达式)
海象运算符 :=
可在表达式内部为变量赋值,虽然官方名称叫赋值表达式,可它的昵称海象运算符更为人熟知,至于昵称的由来其实仔细观察就会发现,它很像海象的眼睛和长牙。
先举个例子:
a='abcdefg'
if len(a)>3:
print(f'
字符串
{a}
的长度是
{len(a)}')
运行结果为:
可以看到,例子中的 len
函数用了两次,这种重复的运算肯定会对性能产生影响。原本我们是可以提前先把 len 函数的值算出来的,可那样又多写了一行,让代码不那么简洁。
那么我们再用海象运算符重新写一下:
a='abcdefg'
if (b:=len(a))>3:
print(f'
字符串
{a}
的长度是
{b}')
运行结果如下:
可以看到, (b:=len(a))
部分其实就是把 len(a)
算出来的值赋值到 b
了,后面我们就能直接使用 b
的值了。
需要注意的是,这里一定要用括号括起来,因为大于号 >
比海象运算符 :=
优先级高,不括起来相当于先计算后面部分,然后赋值给 b 也就是 b:=(len(a)>3)
得到的 b 的值就变成布尔值了。其他一些场合不括起来还可能报错,需要注意。大家可以多多尝试,仔细体会。
下面再来一个有趣的例子,见识一下海象运算符的威力。
相信很多人都用 Python 写过斐波那契数列,使用海象运算符,你甚至可以一行代码实现。
[(f:=(f[1], sum(f)) if i else (0,1))[1] for i in range(10)]
运行结果如下:
海象运算符虽然可以在很多场合使用,但官方也建议尽量将海象运算符的使用限制在清晰的场合中,以降低复杂性并提升可读性。
仅限位置形参
新增了一个函数形参语法 /
用来指明某些函数形参必须使用仅限位置而非关键字参数的形式。/
左侧的参数必须使用位置形参。
另外, *
的右边为仅限关键字形参。
下面的例子中,形参 a 和 b 为仅限位置形参,c 或 d 可以是位置形参或关键字形参,也就是默认形式,而 e 或 f 要求为仅限关键字形参:
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
我们尝试用关键字方式给 a 和 b 赋值,运行结果如下:
可以看到,错误提醒很明确,我们在仅限位置参数的地方放了关键字参数。
如果你把 e 和 f 的关键字去掉,当作位置参数使用,它也会报错。
我们按照正确的要求写入参数,运行结果如下:
另外,在 /
左侧的形参不会被公开为可用关键字,其形参名仍可在 **kwargs 中使用。
举个例子:
def f(a, b, /, **kwargs):
print(a, b, kwargs)
然后我们给后面的参数赋值给 a , b
f(10, 20, a=1, b=2, c=3)
运行结果如下:
可以看到,/ 左侧仅限位置形参的参数名并不影响后面我们后来的操作。
字典可使用 reversed 进行反转
普通字典自 Python 3.7 起已保证具有确定的元素顺序,在 Python 3.8 中可以利用 reversed 按插入顺序反向迭代。Python 字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组
s={'a':23,'b':24,'c':66}
list(reversed(s.items()))
运行结果如下:
f-string 增加 = 说明符
在 f-string 的早期版本,我们要想实现 a = x 的形式,往往比较麻烦。增加 = 说明符用于 f-string。形式为 f'{expr=}' 的 f 字符串将扩展表示为表达式文本,加一个等于号,再加表达式的求值结果。
name = 'Galaxy'
print(f'name = {name}')
运行结果如下:
Python3.8 更新了新的更加简洁的写法,也就是 = 说明符
name = 'Galaxy'
print(f'{name = }')
运行结果如下:
另外,新版本还给 f-string 增加了转换符 !s 、!a 、!r
转换符 '!s' 是对结果调用 str(),'!r' 是调用 repr(),而 '!a' 是调用 ascii()。
我们来举个例子
import datetime
today = datetime.date.today()
print(f'
今天是
{today!s}')
运行结果如下:
repr() 函数将对象转化为供解释器读取的形式。
转换符'!r'的结果如下:
ascii() 函数类似 repr() 函数, 返回一个表示对象的字符串, 但是对于字符串中的非 ASCII 字符则返回通过 repr() 函数使用 \x, \u 或 \U 编码的字符。 生成字符串类似 Python2 版本中 repr() 函数的返回值。
转换符'!a'的结果如下:
可从进程直接访问的共享内存
该模块提供了一个 SharedMemory 类,用于分配和管理多核或对称多处理器(SMP)机器上进程间的共享内存。
介绍一个有趣的新功能,它可以从进程直接访问的共享内存。
我们先打开运行下面代码,获得一个 name 值
from multiprocessing import shared_memory
a = shared_memory.ShareableList([2021, 'abc', 2022])
a
然后打开一个新终端
from multiprocessing import shared_memory b = shared_memory.ShareableList(name=) #这里要把获得的name值写入 b
运行结果如下:
以下示例展示了一个现实中的例子,使用 SharedMemory 类和 NumPy arrays 结合, 从两个 Python shell 中访问同一个 numpy.ndarray :
>>> # In the first Python interactive shell
>>> import numpy as np
>>> a = np.array([1, 1, 2, 3, 5, 8]) # Start with an existing NumPy array
>>> from multiprocessing import shared_memory
>>> shm = shared_memory.SharedMemory(create=True, size=a.nbytes)
>>> # Now create a NumPy array backed by shared memory
>>> b = np.ndarray(a.shape, dtype=a.dtype, buffer=shm.buf)
>>> b[:] = a[:] # Copy the original data into shared memory
>>> b
array([1, 1, 2, 3, 5, 8])
>>> type(b)
<class 'numpy.ndarray'>
>>> type(a)
<class 'numpy.ndarray'>
>>> shm.name # We did not specify a name so one was chosen for us
'psm_21467_46075'
>>> # In either the same shell or a new Python shell on the same machine
>>> import numpy as np
>>> from multiprocessing import shared_memory
>>> # Attach to the existing shared memory block
>>> existing_shm = shared_memory.SharedMemory(name='psm_21467_46075')
>>> # Note that a.shape is (6,) and a.dtype is np.int64 in this example
>>> c = np.ndarray((6,), dtype=np.int64, buffer=existing_shm.buf)
>>> c
array([1, 1, 2, 3, 5, 8])
>>> c[-1] = 888
>>> c
array([ 1, 1, 2, 3, 5, 888])
>>> # Back in the first Python interactive shell, b reflects this change
>>> b
array([ 1, 1, 2, 3, 5, 888])
>>> # Clean up from within the second Python shell
>>> del c # Unnecessary; merely emphasizing the array is no longer used
>>> existing_shm.close()
>>> # Clean up from within the first Python shell
>>> del b # Unnecessary; merely emphasizing the array is no longer used
>>> shm.close()
>>> shm.unlink() # Free and release the shared memory block at the very end
总结
Python 3.8 最让大家期待的就是海象运算符,其他方面还增加仅限位置形参、字典反转、f-string 的 = 用法,另外,很多内置方法的性能都提高了 20% - 50% ,类型提示方面也有一些更新,还是很值得更新使用的。