-
Python 3.7 将引入 dataclass 装饰器
import dataclasses @dataclasses.dataclass class InventoryItem: '''Class for keeping track of an item in inventory.''' name: str unit_price: float quantity_on_hand: int = 0 def total_cost(self) -> float: return self.unit_price * self.quantity_on_hand inv=InventoryItem('PYTHON','200',1) print(f"{inv.unit_price!r}")
我们去掉了init方法,以确保 data class 装饰器可以添加它生成的对应方法。不过,我们在这个过程中失去了一些功能,我们的 Python 3.6 构造函数不仅定义了所有的值,还试图解析日期,我们怎样才能用 data class 来做到这一点呢?
如果要覆盖 init,我们将失去 data class 的优势,因此,如果要处理任何附加功能可以使用新的 dunder 方法:post_init,让我们看看post_init方法对于我们的包装类来说是什么样子的:
def __post_init__(self): if type(self.release_date) is str: self.release_date = dateutil.parser.parse(self.release_date) if type(self.created) is str: self.created = dateutil.parser.parse(self.created) if type(self.edited) is str: self.edited = dateutil.parser.parse(self.edited)
更多好东西
通过使用装饰器的选项,可以为用例进一步定制 data class,默认选项是:
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
init决定是否生成__init__ dunder 方法
repr决定是否生成__repr__ dunder方法
eq对__eq__ dunder 方法也是如此,它决定相等性检查的行为(your_class_instance == another_instance)
order 实际上创建了四种 dunder 方法,它们确定所有检查小于,and/or,大于的行为,如果将其设置为 true,则可以对对象列表进行排序。
最后两个选项确定对象是否可以被哈希化,如果你想使用你的 class 的对象作为字典键的话,这是必要的。
python3.8 新特性
-
:=
引入赋值表达式,可以说是Python3.8 中最大的一个变化了。(:=)形似海象侧牙,也被称为“海象运算符”。赋值表达式可以在统一表达式中赋值并返回值,比如下面的代码,执行给变量分配值,并打印这个值:
walrus = False print(walrus)
可以改为
print(walrus:=True)
应用场景
inputs = list() while (current := input("Write something: ")) != "quit": inputs.append(current)
仅位置参数(Positional-Only Arguments)
def info(name):
print(name)
info(name='python') #python
info('python') #python
但是
def info(name,/):
print(name)
info(name='python'). #error
info('python') #python
通过在 name 之后加入 /,就可以指定 name 为 仅位置参数。常规参数与仅位置参数结合使用,可将常规参数放在 / 之后:
def info(name , / ,sex=1):
print(f'name={name},sex={sex}')
info('python')
info('python',sex=0)
还可以通过按 / 和分隔的顺序组合仅位置、常规和仅关键字参数 *,例如下段代码中,text 是仅位置参数,border 是常规参数(值为默认值),并且 width 是仅关键字参数(值为默认值):
def headline(text, /, border="♦", *, width=50):
return f" {text} ".center(width, border)
**??**什么是仅关键字参数
-
详细类型
def double(number: float) -> float: return int(2 * number) print(double(3.2))
在此示例中,数字应该是浮点数,并且double()函数也应该返回浮点数。但是,Python将这些注释视为提示。它们不会在运行时强制执行:
from typing import Literal def draw_line(direction: Literal["horizontal", "vertical"]) -> None: if direction == "horizontal": ... # Draw horizontal line elif direction == "vertical": ... # Draw vertical line else: raise ValueError(f"invalid direction {direction!r}") draw_line("up")
-
使用f字符串进行更简单的调试
f字符串是在Python 3.6中引入的
def add(a:int,b:int) ->None: print(f'{a = } {b=}') print(f'a={a}, b={b}') print(f'{a=} {b= :.2f}') # :.2f 可以控制输出格式 add(3,4) def show(s:str) ->None: print(f'{s.upper()[::-1] = }') show('abc') #s.upper()[::-1] = 'CBA'
-
新增和改进的数学和统计功能
math.prod()
-
使用isqrt()来找到平方根的整数部分
import math math.isqrt(15) #3
-
使用math.dist()找到两点之间的距离,并通过math.hypot()找到向量的长度:
import math point_1 = (16, 25, 20) point_2 = (8, 15, 14) math.dist(point_1, point_2) math.hypot(*point_1)
这使得使用标准库更容易处理点和向量。但是,如果要对点或向量进行许多计算,则应签出NumPy。 统计模块还具有几个新功能:
statistics.fmean()计算浮点数的平均值。
statistics.geometric_mean()计算浮点数的几何平均值。
statistics.multimode()查找序列中最频繁出现的值。
statistics.quantiles()计算用于将数据等概率分为n个连续区间的切点。import statistics data = [9, 3, 2, 1, 1, 2, 7, 9] statistics.fmean(data)4.25
-
在Python 3.8中,有一个新的statistics.NormalDist类,这使得高斯正态分布更加方便。
要查看使用NormalDist的示例,可以对新的statistics.fmean()和传统的statistics.mean()的速度进行比较:
import random >>> import statistics >>> from timeit import timeit >>> # Create 10,000 random numbers >>> data = [random.random() for _ in range(10_000)] >>> # Measure the time it takes to run mean() and fmean() >>> t_mean = [timeit("statistics.mean(data)", number=100, globals=globals()) ... for _ in range(30)] >>> t_fmean = [timeit("statistics.fmean(data)", number=100, globals=globals()) ... for _ in range(30)] >>> # Create NormalDist objects based on the sampled timings >>> n_mean = statistics.NormalDist.from_samples(t_mean) >>> n_fmean = statistics.NormalDist.from_samples(t_fmean) >>> # Look at sample mean and standard deviation >>> n_mean.mean, n_mean.stdev (0.825690647733245, 0.07788573997674526) >>> n_fmean.mean, n_fmean.stdev (0.010488564966666065, 0.0008572332785645231) >>> # Calculate the lower 1 percentile of mean >>> n_mean.quantiles(n=100)[0] 0.64450132212
-
优化
Python 3.8进行了一些优化,有的让代码运行得更快,有的优化减少了内存占用。例如,与Python 3.7相比,在Python 3.8中查找命名元组中的字段要快得多:
**python 简单了解namedtuple**
namedtuple类位于collections模块,有了namedtuple后通过属性访问数据能够让我们的代码更加的直观更好维护
namedtuple能够用来创建类似于元祖的数据类型,除了能够用索引来访问数据,能够迭代,还能够方便的通过属性名来访问数据
from collections import namedtuple
Friend =namedtuple("Friend",['name','age','email'])
f1=Friend('giga',38,'gaga@qq.com')
print(f1)
print(f1.age)
print(f1.email)
f2=Friend(name='jjuu',email='eeee@qw.com',age=15)
print(f2)
name,age,email=f2
print(name,age,email)
优化体现
>>>
>>> import collections
>>> from timeit import timeit
>>> Person = collections.namedtuple("Person", "name twitter")>>> raymond = Person("Raymond", "@raymondh")
>>> # Python 3.7
>>> timeit("raymond.twitter", globals=globals())
0.05876131607996285
>>> # Python 3.8
>>> timeit("raymond.twitter", globals=globals())
0.0377705999400132
可以看到,在Python 3.8中在namedtuple上查找.twitter的速度提高了30-40%。从具有已知长度的可迭代对象初始化列表时,可以节省一些空间。这样可以节省内存:
>>> import sys
>>> # Python 3.7
>>> sys.getsizeof(list(range(20191014)))
181719232
>>> # Python 3.8
>>> sys.getsizeof(list(range(20191014)))
161528168
本例中,该列表在Python 3.8中使用的内存比Python 3.7少了大约11%。
-
所以,我们必须要更新到 Python3.8 吗?
如果你想尝鲜新功能,那是肯定要升级的。实际产品的开发环境需要升级到 Python3.8 吗?首先,如果在 Python3.8 中运行 3.7 版本代码,问题应该不会很大;Python3.8 的beta版本也试用几个月了,也解决了不少问题,如果能升级到Python3.8,肯定也是安全的,还能在新版本中进行优化。
如果你想尝试一下Python3.8,可以阅读下的文档,以帮助更好的完成移植
https://docs.python.org/3.8/whatsnew/3.8.html#porting-to-python-3-8
还有不能遗漏官方文档: