มีอะไรใหม่ใน Python 3.11

Python 3.11 เร็วกว่า Python 3.10 โดยเฉลี่ยอยู่ที่ ระหว่าง 10-60% 

  • CPython 3.11 นั้นเร็วกว่า CPython 3.10 โดยเฉลี่ย 25% ซึ่งวัดด้วย ชุดมาตรฐาน pyperformance และคอมไพล์ด้วย GCC บน Ubuntu Linux การเพิ่มความเร็วซึ่ง อาจเร็วขึ้นถึง 10-60% ทั้งนี้ขึ้นอยู่กับปริมาณงานของคุณด้วย โดยทั่วไปแล้วหากคุณใช้งานโมดูลที่มีการโหลด IO หนักๆ คุณก็แทบจะไม่เห็นประโยชน์มากนัก
  • ฟังค์ชัน sum() ตอนนี้เร็วขึ้นเกือบ 30% สำหรับจำนวนเต็มที่น้อยกว่า 2**30 หรือ 1073741824
  • ตอนนี้คอมไพเลอร์ปรับ  printf-style % formatting แบบง่ายให้เหมาะสมที่สุดบนตัวอักษรสตริงที่มีรูปแบบโค้ดเฉพาะอย่าง %s%r และ %a และทำให้ความเร็วสอดคล้องเท่ากันกับ f-string
  • การหารเป็นจำนวนเต็ม (//) ได้รับการปรับแต่งให้ดีขึ้นสำหรับการเพิ่มประสิทธิภาพจากคอมไพเลอร์ ตอนนี้ x86 และ x64 เร็วขึ้นประมาณ 20% เมื่อหารเป็น int โดยค่าต้องน้อยกว่า2**30 หรือ 1073741824
  • การปรับขนาดของ list ให้มีความคล่องตัวสำหรับการใช้งานทั่วไป โดย list.append() เร็วขึ้น 15% และlist comprehension เร็วขึ้น 20-30%
  • การใช้asyncio.DatagramProtocolงานจะเร็วขึ้นเมื่อถ่ายโอนไฟล์ขนาดใหญ่ผ่าน UDP ด้วยความเร็วสูงกว่า 100 เท่า สำหรับไฟล์ประมาณ 60 MiB
  • [math](https://docs.python.org/3.11/library/math.html#module-math “คณิตศาสตร์: ฟังก์ชันทางคณิตศาสตร์ (sin() เป็นต้น) ฟังก์ชัน comb()และ perm()ตอนนี้เร็วขึ้นประมาณ 10 เท่า สำหรับอาร์กิวเมนต์ที่มีขนาดใหญ่ (ด้วยการเพิ่มความเร็วที่มากขึ้นและค่า k ที่ใหญ่ขึ้น )
  • statisticsฟังก์ชัน mean()และ variance()และ stdev()ตอนนี้ใช้ตัววนซ้ำรอบเดียวและแปลงเป็นฟังก์ชัน listก่อน ซึ่งเร็วกว่าสองเท่าและสามารถประหยัดการใช้หน่วยความจำไปได้มาก
  • unicodedata.normalize() ตอนนี้ทำให้สตริง pure-ASCII เป็นปกติในเวลาคงที่

คุณสมบัติ syntax และ built-in ใหม่

  • PEP 654: Exception Groups และ except* คุณสมบัติที่จะช่วยให้โปรแกรมสามารถ raise และจัดการ Exception ที่ไม่เกี่ยวข้องในหลายๆรายการพร้อมกันได้ บิวด์อินประเภทExceptionGroupและBaseExceptionGroup ทำให้สามารถจัดกลุ่ม Exception และรวมกันได้ และ except*ไวยากรณ์ใหม่จะสรุป exceptให้ตรงกับกลุ่มย่อยของกลุ่ม Exception
>>> eg = ExceptionGroup(
...     "one",
...     [
...         TypeError(1),
...         ExceptionGroup(
...             "two",
...              [TypeError(2), ValueError(3)]
...         ),
...         ExceptionGroup(
...              "three",
...               [OSError(4)]
...         )
...     ]
... )
>>> import traceback
>>> traceback.print_exception(eg)
  | ExceptionGroup: one (3 sub-exceptions)
  +-+---------------- 1 ----------------
    | TypeError: 1
    +---------------- 2 ----------------
    | ExceptionGroup: two (2 sub-exceptions)
    +-+---------------- 1 ----------------
      | TypeError: 2
      +---------------- 2 ----------------
      | ValueError: 3
      +------------------------------------
    +---------------- 3 ----------------
    | ExceptionGroup: three (1 sub-exception)
    +-+---------------- 1 ----------------
      | OSError: 4
      +------------------------------------

>>> type_errors = eg.subgroup(lambda e: isinstance(e, TypeError))
>>> traceback.print_exception(type_errors)
  | ExceptionGroup: one (2 sub-exceptions)
  +-+---------------- 1 ----------------
    | TypeError: 1
    +---------------- 2 ----------------
    | ExceptionGroup: two (1 sub-exception)
    +-+---------------- 1 ----------------
      | TypeError: 2
      +------------------------------------
>>>
  • PEP 678: Exceptions สามารถเสริมโน้ตลงไปได้ เมธอด add_note()ถูกเพิ่มเข้าไปใน BaseExceptionสามารถใช้เพื่อเพิ่มข้อ Exception ด้วยข้อมูล context ที่ไม่พร้อมใช้งานในขณะที่ raise Exception ออกมาแล้ว โน้ตที่เพิ่มเข้ามาจะปรากฏใน traceback เริ่มต้น
>>> try:
...     raise TypeError('bad type')
... except Exception as e:
...     e.add_note('เพิ่มข้อมูลบางอย่าง')
...     raise
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: bad type
เพิ่มขอมลบางอยาง
>>>

โมดูลไลบรารีมาตรฐานใหม่

  • PEP 680 : tomllib — รองรับการแยกวิเคราะห์ TOML ในไลบรารีมาตรฐาน โมดูลนี้มีอินเทอร์เฟซสำหรับการแยกวิเคราะห์ TOML (Tom’s Obvious Minimal Language, https://toml.io ) โมดูลนี้ไม่รองรับการเขียนแบบ TOML

  • การแยกวิเคราะห์ด้วยไฟล์ .TOML

import tomllib

with open("pyproject.toml", "rb") as f:
    data = tomllib.load(f)
  • การแยกวิเคราะห์ด้วยสตริง TOML:
import tomllib

toml_str = """
python-version = "3.11.0"
python-implementation = "CPython"
"""

data = tomllib.loads(toml_str)

ปรับปรุงตัวแปลคำสั่งหรืออินเทอร์พรีเตอร์ (Interpreter)

  • PEP 657: ตำแหน่งของข้อผิดพลาดที่ละเอียดจากการ traceback เมื่อแสดงข้อมูล  traceback ตอนนี้ตัวแปลคำสั่งจะชี้ไปยังนิพจน์หรือ expression ที่แน่นอนขึ้นบริเวณที่ทำให้เกิดข้อผิดพลาด แทนที่จะระบุเป็นเพียงบรรทัด ตัวอย่างเช่น:
Traceback (most recent call last):
  File "distance.py", line 11, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "distance.py", line 6, in manhattan_distance
    return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                           ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'

*ให้สังเกตุที่เครื่องหมาย ^^^^^^^^^ ที่แสดงอยูในโค้ดตัวอย่าง

  • -Pตัวเลือกบรรทัดคำสั่งใหม่เพิ่มเติม และตัวแปร environment PYTHONSAFEPATH เพื่อปิดใช้งานการเติม sys.path หน้าไดเร็กทอรีของสคริปต์โดยอัตโนมัติเมื่อเรียกใช้งานสคริปต์ หรือไดเร็กทอรีปัจจุบันเมื่อใช้ -c และ -m สิ่งนี้ทำให้แน่ใจว่าเฉพาะโมดูล stdlib และโมดูลที่ติดตั้งเท่านั้นที่จะถูกเลือกจากการ importเข้ามาเพื่อหลีกเลี่ยงการ shadowing modules โดยไม่ได้ตั้งใจหรือมุ่งร้ายกับโมดูลที่อยู่ในไดเร็กทอรีท้องถิ่น

คุณสมบัติใหม่ที่เกี่ยวข้องกับคำแนะนำประเภท

  • PEP 646: Variadic generics โดย TypeVarTuple เปิดใช้งานการกำหนดพารามิเตอร์ด้วยจำนวนประเภทได้ตามอำเภอใจ ช่วยให้ใช้งานได้หลากหลายขึ้น โดยเฉพาะอย่างยิ่ง อนุญาตให้กำหนดประเภทของโครงสร้างที่เหมือนอาร์เรย์ในไลบรารีการคำนวณเชิงตัวเลข เช่น NumPy และ TensorFlow สามารถArray ใช้เพื่อสนับสนุนคำอธิบายประกอบเกี่ยวกับ shape ได้หลายประเภท ตัวอย่างเช่น เราสามารถเพิ่มป้ายกำกับที่อธิบายความหมายเชิงความหมายของแต่ละแกน
from typing import NewType

Height = NewType('Height', int)
Width = NewType('Width', int)

x: Array[float, Height, Width] = Array()
  • PEP 655: การทำเครื่องหมายแต่ละ TypedDict รายการว่าจำเป็นหรือไม่จำเป็น Required กับ NotRequiredให้วิธีการที่ตรงไปตรงมาในการทำเครื่องหมายว่าต้องมีรายการแต่ละ รายการใน TypedDict หรือไม่ ซึ่งก่อนหน้านี้ทำได้โดยใช้การสืบทอดเพียงอย่างเดียวเท่านั้น ฟิลด์ทั้งหมดค่าเริ่มต้นจะเป็น required เว้นแต่ว่าหากพารามิเตอร์ total เป็น False ซึ่งในกรณีนี้ฟิลด์ทั้งหมดค่าเริ่มต้นจะเป็น not-required ตัวอย่างเช่น ข้อมูลต่อไปนี้ระบุ TypedDict ด้วยหนึ่งคีย์เป็น required
 class Movie(TypedDict):
   title: str
   year: NotRequired[int]

m1: Movie = {"title": "Black Panther", "year": 2018}  # OK
m2: Movie = {"title": "Star Wars"}  # OK (year is not required)
m3: Movie = {"year": 2022}  # ERROR (missing required field title)

และหนึ่งคีย์ not-required

class Movie(TypedDict, total=False):
   title: Required[str]
   year: int
  • PEP 673: Self type คำอธิบายประกอบ Self ใหม่ เป็นวิธีที่ง่ายและใช้งานง่ายในการใส่คำอธิบายประกอบของเมธอด ที่ return อินสแตนซ์ของ class สิ่งนี้ทำงานเหมือนกับแนวทางที่ใช้กับ TypeVar แต่กระชับและง่ายในทางปฏิบัติตามมาก กรณีการใช้งานทั่วไปรวมถึงตัวสร้างที่เป็นทางเลือกที่จัดไว้ให้คือ @classmethod และเมธอด __enter__() และส่งค่า self กลับ
class MyLock:
    def __enter__(self) -> Self:
        self.lock()
        return self

    ...

class MyInt:
    @classmethod
    def fromhex(cls, s: str) -> Self:
        return cls(int(s, 16))

    ...
  • PEP 675: ประเภทสตริงตามอำเภอใจ อาจใช้เพื่อระบุว่าพารามิเตอร์ของฟังก์ชันสามารถเป็นประเภทสตริงตามตัวอักษรใดก็ได้ ซึ่งช่วยให้ฟังก์ชันยอมรับประเภทสตริงตามตัวอักษรได้ เช่นเดียวกับสตริงที่สร้างจากสตริงตามตัวอักษรอื่นๆ ตัวตรวจสอบประเภทสามารถบังคับใช้ฟังก์ชันที่ละเอียดอ่อนได้ เช่น ฟังก์ชันที่ดำเนินการคำสั่ง SQL หรือคำสั่งเชลล์ จะถูกเรียกด้วยอาร์กิวเมนต์แบบคงที่เท่านั้น ซึ่งให้การป้องกันการโจมตีแบบ injection ตัวอย่างเช่น ฟังก์ชันSQL query สามารถใส่คำอธิบายประกอบได้ดังนี้:
def run_query(sql: LiteralString) -> ...
    ...

def caller(
    arbitrary_string: str,
    query_string: LiteralString,
    table_name: LiteralString,
) -> None:
    run_query("SELECT * FROM students")       # ok
    run_query(query_string)                   # ok
    run_query("SELECT * FROM " + table_name)  # ok
    run_query(arbitrary_string)               # type checker error
    run_query(                                # type checker error
        f"SELECT * FROM students WHERE name = {arbitrary_string}"
    )
  • PEP 681: Data class transforms อาจใช้ตกแต่งคลาส เมตาคลาส หรือฟังก์ชันที่เป็น decorator การมีอยู่ของ @dataclass_transform() บอกตัวตรวจสอบประเภทสแตติกว่าอ็อบเจ็กต์ที่ตกแต่งแล้วเท่านั้นถึงจะดำเนินการ “magic” รันไทม์ที่เปลี่ยนคลาสทำให้มี dataclass พฤติกรรมเหมือนมัน
# decorator create_model ถูกกำหนดโดย library
@typing.dataclass_transform()
def create_model(cls: Type[T]) -> Type[T]:
    cls.__init__ = ...
    cls.__eq__ = ...
    cls.__ne__ = ...
    return cls

# decorator create_model ตอนนี้สามารถใช้เพื่อสร้างคลาสโมเดลใหม่ได้เลยทันที
@create_model
class CustomerModel:
    id: int
    name: str

c = CustomerModel(id=327, name="Eric Idle")