其他
@程序员:Python 3.8正式发布,重要新功能都在这里
Python3.8有哪些你要关注的新内容?
新功能手册: https://docs.python.org/3.8/whatsnew/3.8.html
使用赋值表达式简化一些代码结构 在你自己的函数中强制执行仅位置参数 指定更精确的类型提示 使用f字符串进行更简单的调试
一、赋值表达式(Assignment expressions)
>>> walrus = False
>>> print(walrus)
False
>>> print(walrus := True)
True
inputs = list()
current = input("Write something: ")
while current != "quit":
inputs.append(current)
current = input("Write something: ")
inputs = list()
while True:
current = input("Write something: ")
if current == "quit":
break
inputs.append(current)
inputs = list()
while (current := input("Write something: ")) != "quit":
inputs.append(current)
PEP572中描述了复制表达式的所有细节,大家可以深入阅读。 https://www.python.org/dev/peps/pep-0572/ https://www.python.org/dev/peps/pep-0572/#examples
仅位置参数(Positional-Only Arguments)
>>> float("3.8")
3.8
>>> help(float)
class float(object)
| float(x=0, /)
|
| Convert a string or number to a floating point number, if possible.
[...]
PEP 457 -- Notation For Positional-Only Parameters https://www.python.org/dev/peps/pep-0457/
>>> float(x="3.8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: float() takes no keyword arguments
>>> def incr(x):
... return x + 1
...
>>> incr(3.8)
4.8
>>> incr(x=3.8)
4.8
>>> def incr(x, /):
... return x + 1
...
>>> incr(3.8)
4.8
>>> incr(x=3.8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: incr() got some positional-only arguments passed as
keyword arguments: 'x'
>>> def greet(name, /, greeting="Hello"):
... return f"{greeting}, {name}"
...
>>> greet("Łukasz")
'Hello, Łukasz'
>>> greet("Łukasz", greeting="Awesome job")
'Awesome job, Łukasz'
>>> greet(name="Łukasz", greeting="Awesome job")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: greet() got some positional-only arguments passed as
keyword arguments: 'name'
>>> def to_fahrenheit(*, celsius):
... return 32 + celsius * 9 / 5
...
>>> to_fahrenheit(40)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: to_fahrenheit() takes 0 positional arguments but 1 was given
>>> to_fahrenheit(celsius=40)
104.0
>>> def headline(text, /, border="♦", *, width=50):
... return f" {text} ".center(width, border)
...
>>> headline("Positional-only Arguments")
'♦♦♦♦♦♦♦♦♦♦♦ Positional-only Arguments ♦♦♦♦♦♦♦♦♦♦♦♦'
>>> headline(text="This doesn't work!")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: headline() got some positional-only arguments passed as
keyword arguments: 'text'
>>> headline("Python 3.8", "=")
'=================== Python 3.8 ==================='
>>> headline("Real Python", border=":")
':::::::::::::::::: Real Python :::::::::::::::::::'
>>>
>>> headline("Python", "🐍", width=38)
'🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍 Python 🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍🐍'
>>> headline("Python", "🐍", 38)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: headline() takes from 1 to 2 positional arguments
but 3 were given
关于仅位置参数的内容可以阅读 PEP 570 文档:https://www.python.org/dev/peps/pep-0570/
更多详细类型
文字类型 打字字典 最终对象 协定
def double(number: float) -> float:
return 2 * number
>>> double(3.14)
6.28
>>> double("I'm not a float")
"I'm not a floatI'm not a float"
$ python -m pip mypy
PEP 484 https://www.python.org/dev/peps/pep-0484/
# draw_line.py
def draw_line(direction: str) -> None:
if direction == "horizontal":
... # Draw horizontal line
elif direction == "vertical":
... # Draw vertical line
else:
raise ValueError(f"invalid direction {direction!r}")
draw_line("up")
# draw_line.py
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")
$ mypy draw_line.py
draw_line.py:15: error:
Argument 1 to "draw_line" has incompatible type "Literal['up']";
expected "Union[Literal['horizontal'], Literal['vertical']]"
Found 1 error in 1 file (checked 1 source file)
Union[Literal["horizontal"], Literal["vertical"]]
# calculator.py
from typing import Union
ARABIC_TO_ROMAN = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"),
(100, "C"), (90, "XC"), (50, "L"), (40, "XL"),
(10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")]
def _convert_to_roman_numeral(number: int) -> str:
"""Convert number to a roman numeral string"""
result = list()
for arabic, roman in ARABIC_TO_ROMAN:
count, number = divmod(number, arabic)
result.append(roman * count)
return "".join(result)
def add(num_1: int, num_2: int, to_roman: bool = True) -> Union[str, int]:
"""Add two numbers"""
result = num_1 + num_2
if to_roman:
return _convert_to_roman_numeral(result)
else:
return result
# calculator.py
from typing import Literal, overload, Union
ARABIC_TO_ROMAN = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"),
(100, "C"), (90, "XC"), (50, "L"), (40, "XL"),
(10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")]
def _convert_to_roman_numeral(number: int) -> str:
"""Convert number to a roman numeral string"""
result = list()
for arabic, roman in ARABIC_TO_ROMAN:
count, number = divmod(number, arabic)
result.append(roman * count)
return "".join(result)
@overload
def add(num_1: int, num_2: int, to_roman: Literal[True]) -> str: ...
@overload
def add(num_1: int, num_2: int, to_roman: Literal[False]) -> int: ...
def add(num_1: int, num_2: int, to_roman: bool = True) -> Union[str, int]:
"""Add two numbers"""
result = num_1 + num_2
if to_roman:
return _convert_to_roman_numeral(result)
else:
return result
from typing import Final
ID: Final = 1
...
ID += 1
from typing import final
@final
class Base:
...
class Sub(Base):
..
py38 = {"version": "3.8", "release_year": 2019}
from typing import TypedDict
class PythonVersion(TypedDict):
version: str
release_year: int
py38 = PythonVersion(version="3.8", release_year=2019
py38: PythonVersion = {"version": "3.8", "release_year": 2019}
当我看到一只鸟走路像鸭子,游泳像鸭子,像鸭子一样嘎嘎叫时,我把它称为鸭子。
from typing import Protocol
class Named(Protocol):
name: str
def greet(obj: Named) -> None:
print(f"Hi {obj.name}"
>>>
>>> style = "formatted"
>>> f"This is a {style} string"
'This is a formatted string'
>>> import math
>>> r = 3.6
>>> f"A circle with radius {r} has area {math.pi * r * r:.2f}"
'A circle with radius 3.6 has area 40.72'
官方文档 https://docs.python.org/3/library/string.html#format-specification-mini-language
>>> import math
>>> r = 3.8
>>> f"Diameter {(diam := 2 * r)} gives circumference {math.pi * diam:.2f}"
'Diameter 7.6 gives circumference 23.88'
>>> python = 3.8
>>> f"{python=}"
'python=3.8'
>>> python = 3.7
>>> f"python={python}"
'python=3.7'
>>> name = "Eric"
>>> f"{name = }"
"name = 'Eric'"
>>> f"{name = :>10}"
'name = Eric'
>>> f"{name.upper()[::-1] = }"
"name.upper()[::-1] = 'CIRE'"
指导委员会模式(The Python Steering Council)
Barry Warsaw Brett Cannon Carol Willing Guido van Rossum Nick Coghlan
其他酷炫的新功能
importlib.metadata
importlib.metadata
>>> from importlib import metadata
>>> metadata.version("pip")
'19.2.3'
>>> pip_metadata = metadata.metadata("pip")
>>> list(pip_metadata)
['Metadata-Version', 'Name', 'Version', 'Summary', 'Home-page', 'Author',
'Author-email', 'License', 'Keywords', 'Platform', 'Classifier',
'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier',
'Classifier', 'Classifier', 'Classifier', 'Classifier', 'Classifier',
'Classifier', 'Classifier', 'Requires-Python']
>>> pip_metadata["Home-page"]
'https://pip.pypa.io/'
>>> pip_metadata["Requires-Python"]
'>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*'
>>> len(metadata.files("pip"))
668
>>> [p for p in metadata.files("realpython-reader") if p.suffix == ".py"]
[PackagePath('reader/__init__.py'), PackagePath('reader/__main__.py'),
PackagePath('reader/feed.py'), PackagePath('reader/viewer.py')]
>>> init_path = _[0] # Underscore access last returned value in the REPL
>>> print(init_path.read_text())
"""Real Python feed reader
Import the `feed` module to work with the Real Python feed:
>>> from reader import feed
>>> feed.get_titles()
['Logging in Python', 'The Best Python Books', ...]
See https://github.com/realpython/reader/ for more information
"""
# Version of realpython-reader package
__version__ = "1.0.0"
...
>>> metadata.requires("realpython-reader")
['feedparser', 'html2text', 'importlib-resources', 'typing']
try:
from importlib import metadata
except ImportError:
import importlib_metadata as metadata
...
新增和改进的数学和统计功能
>>> import math
>>> math.prod((2, 8, 7, 7))
784
>>> 2 * 8 * 7 * 7
784
>>> import math>>> math.isqrt(9)3>>> math.sqrt(9)3.0
>>> math.isqrt(15)
3
>>> math.sqrt(15)
3.8729833462074
>>> import math
>>> point_1 = (16, 25, 20)
>>> point_2 = (8, 15, 14)
>>> math.dist(point_1, point_2)
14.142135623730951
>>> math.hypot(*point_1)
35.79106033634656
>>> math.hypot(*point_2)
22.022715545545
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
>>> statistics.geometric_mean(data)
3.013668912157617
>>> statistics.multimode(data)
[9, 2, 1]
>>> statistics.quantiles(data, n=4)
[1.25, 2.5, 8.5]
>>> 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.7
>>> version = "3.7"
>>> version is "3.7"
False
>>> # Python 3.8
>>> version = "3.8"
>>> version is "3.8"
<stdin>:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
False
>>> version == "3.8"
True
>>> [
... (1, 3)
... (2, 4)
... ]
<stdin>:2: SyntaxWarning: 'tuple' object is not callable; perhaps
you missed a comma?
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: 'tuple' object is not callable
优化
优化
>>>
>>> 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
>>> import sys
>>> # Python 3.7
>>> sys.getsizeof(list(range(20191014)))
181719232
>>> # Python 3.8
>>> sys.getsizeof(list(range(20191014)))
161528168
所以,我们必须要更新到 Python3.8 吗?
https://docs.python.org/3.8/whatsnew/3.8.html#porting-to-python-3-8
https://www.python.org/downloads/release/python-380/
https://realpython.com/python38-new-features/ https://docs.python.org/3.8/whatsnew/3.8.html
◆
精彩推荐
◆
推荐阅读
网红“AI大佬”被爆论文剽窃,Jeff Dean都看不下去了
AI大佬“互怼”:Bengio和Gary Marcus隔空对谈深度学习发展现状
有了这套模板,再不担心刷不动LeetCode了
Google图嵌入工业界最新大招,高效解决训练大规模深度图卷积神经网络问题
太鸡冻了!我用Python偷偷查到暗恋女生的名字
苹果 5G 芯片“难产”
【角度刁钻】如果把线程当作一个人来对待,秒懂
C 语言这么厉害,它自身是用什么语言写的?
一文了解超级账本DLT、库、开发工具有哪些, Hyperledger家族成员你认识几个?
你点的每个“在看”,我都认真当成了AI