annotationlib --- Chức năng xem xét các chú thích

Added in version 3.14.

Source code: Lib/annotationlib.py


Mô-đun annotationlib cung cấp các công cụ để tìm hiểu annotations về các mô-đun, lớp và hàm.

Chú thích là lazily evaluated và thường chứa các tham chiếu chuyển tiếp tới các đối tượng chưa được xác định khi chú thích được tạo. Mô-đun này cung cấp một bộ công cụ cấp thấp có thể được sử dụng để truy xuất các chú thích một cách đáng tin cậy, ngay cả khi có các tham chiếu chuyển tiếp và các trường hợp biên khác.

Mô-đun này hỗ trợ truy xuất chú thích ở ba định dạng chính (xem Format), mỗi định dạng hoạt động tốt nhất cho các trường hợp sử dụng khác nhau:

  • VALUE đánh giá các chú thích và trả về giá trị của chúng. Cách này dễ thực hiện nhất nhưng có thể gây ra lỗi, ví dụ: nếu chú thích chứa tham chiếu đến tên không xác định.

  • FORWARDREF trả về đối tượng ForwardRef cho các chú thích không thể giải quyết được, cho phép bạn kiểm tra các chú thích mà không cần đánh giá chúng. Điều này hữu ích khi bạn cần làm việc với các chú thích có thể chứa các tham chiếu chuyển tiếp chưa được giải quyết.

  • STRING trả về các chú thích dưới dạng một chuỗi, tương tự như cách nó xuất hiện trong tệp nguồn. Điều này hữu ích cho những người tạo tài liệu muốn hiển thị chú thích theo cách dễ đọc.

Hàm get_annotations() là điểm vào chính để truy xuất chú thích. Với một hàm, lớp hoặc mô-đun, nó trả về một từ điển chú thích theo định dạng được yêu cầu. Mô-đun này cũng cung cấp chức năng để làm việc trực tiếp với annotate function được sử dụng để đánh giá các chú thích, chẳng hạn như get_annotate_from_class_namespace()call_annotate_function(), cũng như chức năng call_evaluate_function() để làm việc với evaluate functions.

Cảnh báo

Hầu hết chức năng trong mô-đun này có thể thực thi mã tùy ý; xem the security section để biết thêm thông tin.

Xem thêm

PEP 649 đã đề xuất mô hình hiện tại về cách hoạt động của các chú thích trong Python.

PEP 749 đã mở rộng trên nhiều khía cạnh khác nhau của PEP 649 và giới thiệu mô-đun annotationlib.

Các phương pháp hay nhất về chú thích cung cấp các phương pháp hay nhất để làm việc với chú thích.

typing-extensions cung cấp một backport của get_annotations() hoạt động trên các phiên bản Python cũ hơn.

Ngữ nghĩa chú thích

Cách đánh giá các chú thích đã thay đổi trong lịch sử của Python 3 và hiện vẫn phụ thuộc vào future import. Đã có các mô hình thực thi cho chú thích:

  • Stock semantics (mặc định trong Python 3.0 đến 3.13; xem PEP 3107PEP 526): Các chú thích được đánh giá một cách háo hức vì chúng gặp phải trong mã nguồn.

  • Stringified annotations (được sử dụng với from __future__ import annotations trong Python 3.7 trở lên; xem PEP 563): Chú thích chỉ được lưu trữ dưới dạng chuỗi.

  • Deferred evaluation (mặc định trong Python 3.14 trở lên; xem PEP 649PEP 749): Các chú thích chỉ được đánh giá một cách lười biếng, chỉ khi chúng được truy cập.

Ví dụ, hãy xem xét chương trình sau:

def func(a: Cls) -> Không :
    in (a)

lớp Cls: đậu

print(func.__annotations__)

Điều này sẽ hành xử như sau:

  • Theo ngữ nghĩa gốc (Python 3.13 trở về trước), nó sẽ ném NameError vào dòng nơi func được xác định, bởi vì Cls là tên không xác định tại thời điểm đó.

  • Dưới các chú thích được xâu chuỗi (nếu sử dụng from __future__ import annotations), nó sẽ in {'a': 'Cls', 'return': 'None'}.

  • Theo đánh giá trì hoãn (Python 3.14 trở lên), nó sẽ in {'a': <class 'Cls'>, 'return': None}.

Ngữ nghĩa gốc được sử dụng khi chú thích hàm lần đầu tiên được giới thiệu trong Python 3.0 (bởi PEP 3107) vì đây là cách đơn giản nhất, rõ ràng nhất để triển khai chú thích. Mô hình thực thi tương tự đã được sử dụng khi các chú thích biến được giới thiệu trong Python 3.6 (bởi PEP 526). Tuy nhiên, ngữ nghĩa gốc gây ra vấn đề khi sử dụng chú thích làm gợi ý loại, chẳng hạn như cần tham chiếu đến các tên chưa được xác định khi gặp chú thích. Ngoài ra, còn có vấn đề về hiệu suất khi thực thi chú thích tại thời điểm nhập mô-đun. Do đó, trong Python 3.7, PEP 563 đã giới thiệu khả năng lưu trữ chú thích dưới dạng chuỗi bằng cú pháp from __future__ import annotations. Kế hoạch vào thời điểm đó cuối cùng là đặt hành vi này thành mặc định, nhưng một vấn đề đã xuất hiện: các chú thích được xâu chuỗi khó xử lý hơn đối với những người xem xét kỹ các chú thích trong thời gian chạy. Một đề xuất thay thế, PEP 649, đã giới thiệu mô hình thực thi thứ ba, đánh giá trì hoãn và được triển khai trong Python 3.14. Các chú thích dạng chuỗi vẫn được sử dụng nếu có from __future__ import annotations nhưng hành vi này cuối cùng sẽ bị xóa.

Lớp học

class annotationlib.Format

Một IntEnum mô tả các định dạng có thể trả về các chú thích. Các thành viên của enum hoặc các giá trị số nguyên tương đương của chúng có thể được truyền cho get_annotations() và các hàm khác trong mô-đun này, cũng như cho các hàm __annotate__.

VALUE = 1

Các giá trị là kết quả của việc đánh giá các biểu thức chú thích.

VALUE_WITH_FAKE_GLOBALS = 2

Giá trị đặc biệt được sử dụng để báo hiệu rằng hàm chú thích đang được đánh giá trong một môi trường đặc biệt có toàn cầu giả. Khi được chuyển giá trị này, các hàm chú thích sẽ trả về cùng giá trị như đối với định dạng Format.VALUE hoặc tăng NotImplementedError để báo hiệu rằng chúng không hỗ trợ thực thi trong môi trường này. Định dạng này chỉ được sử dụng nội bộ và không được chuyển cho các chức năng trong mô-đun này.

FORWARDREF = 3

Giá trị là các giá trị chú thích thực (theo định dạng Format.VALUE) cho các giá trị được xác định và proxy ForwardRef cho các giá trị không xác định. Các đối tượng thực có thể chứa các tham chiếu đến các đối tượng proxy ForwardRef.

STRING = 4

Giá trị là chuỗi văn bản của chú thích như nó xuất hiện trong mã nguồn, có thể sửa đổi bao gồm nhưng không giới hạn ở việc chuẩn hóa khoảng trắng và tối ưu hóa giá trị không đổi.

Giá trị chính xác của các chuỗi này có thể thay đổi trong các phiên bản Python trong tương lai.

Added in version 3.14.

class annotationlib.ForwardRef

Một đối tượng proxy để tham chiếu chuyển tiếp trong chú thích.

Các phiên bản của lớp này được trả về khi định dạng FORWARDREF được sử dụng và các chú thích chứa tên không thể giải quyết được. Điều này có thể xảy ra khi tham chiếu chuyển tiếp được sử dụng trong chú thích, chẳng hạn như khi một lớp được tham chiếu trước khi nó được xác định.

__forward_arg__

Một chuỗi chứa mã được đánh giá để tạo ra ForwardRef. Chuỗi có thể không tương đương chính xác với nguồn ban đầu.

evaluate(*, owner=None, globals=None, locals=None, type_params=None, format=Format.VALUE)

Đánh giá tham chiếu chuyển tiếp, trả về giá trị của nó.

Nếu đối số formatVALUE (mặc định), phương thức này có thể đưa ra một ngoại lệ, chẳng hạn như NameError, nếu tham chiếu chuyển tiếp đề cập đến một tên không thể giải quyết được. Các đối số của phương thức này có thể được sử dụng để cung cấp các ràng buộc cho các tên mà lẽ ra không được xác định. Nếu đối số formatFORWARDREF, phương thức sẽ không bao giờ đưa ra ngoại lệ nhưng có thể trả về một phiên bản ForwardRef. Ví dụ: nếu đối tượng tham chiếu chuyển tiếp chứa mã list[undefined], trong đó undefined là tên không được xác định thì việc đánh giá nó bằng định dạng FORWARDREF sẽ trả về list[ForwardRef('undefined')]. Nếu đối số formatSTRING, phương thức sẽ trả về __forward_arg__.

Tham số owner cung cấp cơ chế ưu tiên để truyền thông tin phạm vi cho phương thức này. Chủ sở hữu của ForwardRef là đối tượng chứa chú thích mà từ đó ForwardRef xuất phát, chẳng hạn như đối tượng mô-đun, đối tượng loại hoặc đối tượng hàm.

Các tham số globals, localstype_params cung cấp một cơ chế chính xác hơn để tác động đến các tên có sẵn khi ForwardRef được đánh giá. globalslocals được chuyển đến eval(), đại diện cho các không gian tên cục bộ và toàn cầu mà tên được đánh giá. Tham số type_params có liên quan đến các đối tượng được tạo bằng cú pháp gốc cho generic classesfunctions. Đó là một bộ type parameters nằm trong phạm vi trong khi tham chiếu chuyển tiếp đang được đánh giá. Ví dụ: nếu đánh giá một ForwardRef được truy xuất từ ​​một chú thích được tìm thấy trong không gian tên lớp của một lớp chung C, thì type_params phải được đặt thành C.__type_params__.

Các phiên bản ForwardRef được get_annotations() trả về giữ lại các tham chiếu đến thông tin về phạm vi mà chúng bắt nguồn từ đó, vì vậy, việc gọi phương thức này mà không có đối số nào khác có thể đủ để đánh giá các đối tượng đó. Các phiên bản ForwardRef được tạo bằng các phương tiện khác có thể không có bất kỳ thông tin nào về phạm vi của chúng, do đó, việc chuyển đối số cho phương thức này có thể cần thiết để đánh giá chúng thành công.

Nếu không cung cấp owner, globals, locals hoặc type_paramsForwardRef không chứa thông tin về nguồn gốc của nó, thì từ điển toàn cầu và địa phương trống sẽ được sử dụng.

Added in version 3.14.

Chức năng

annotationlib.annotations_to_string(annotations)

Chuyển đổi một lệnh chú thích chứa các giá trị thời gian chạy thành một lệnh chỉ chứa các chuỗi. Nếu các giá trị chưa phải là chuỗi, chúng sẽ được chuyển đổi bằng type_repr(). Điều này có nghĩa là một trình trợ giúp cho các hàm chú thích do người dùng cung cấp hỗ trợ định dạng STRING nhưng không có quyền truy cập vào mã tạo chú thích.

Ví dụ: điều này được sử dụng để triển khai STRING cho các lớp typing.TypedDict được tạo thông qua cú pháp hàm:

>>> từ cách nhập nhập TypedDict
>>> Phim = TypedDict("phim", {"name": str, "year": int})
>>> get_annotations(Phim, định dạng=Format.STRING)
{'name': 'str', 'năm': 'int'}

Added in version 3.14.

annotationlib.call_annotate_function(annotate, format, *, owner=None)

Gọi annotate function annotate với format đã cho, một thành viên của Format enum và trả về từ điển chú thích do hàm tạo ra.

Hàm trợ giúp này là bắt buộc vì các hàm chú thích do trình biên dịch tạo ra cho các hàm, lớp và mô-đun chỉ hỗ trợ định dạng VALUE khi được gọi trực tiếp. Để hỗ trợ các định dạng khác, hàm này gọi hàm chú thích trong một môi trường đặc biệt cho phép nó tạo chú thích ở các định dạng khác. Đây là một khối xây dựng hữu ích khi triển khai chức năng cần đánh giá một phần chú thích trong khi một lớp đang được xây dựng.

owner là đối tượng sở hữu chức năng chú thích, thường là hàm, lớp hoặc mô-đun. Nếu được cung cấp, nó sẽ được sử dụng ở định dạng FORWARDREF để tạo ra đối tượng ForwardRef mang nhiều thông tin hơn.

Xem thêm

PEP 649 chứa phần giải thích về kỹ thuật triển khai được chức năng này sử dụng.

Added in version 3.14.

annotationlib.call_evaluate_function(evaluate, format, *, owner=None)

Gọi evaluate function evaluate với format đã cho, một thành viên của enum Format và trả về giá trị do hàm tạo ra. Điều này tương tự như call_annotate_function(), nhưng cái sau luôn trả về một chuỗi ánh xạ từ điển tới các chú thích, trong khi hàm này trả về một giá trị duy nhất.

Điều này được thiết kế để sử dụng với các hàm đánh giá được tạo cho các phần tử được đánh giá lười biếng liên quan đến bí danh loại và tham số loại:

owner là đối tượng sở hữu hàm đánh giá, chẳng hạn như bí danh loại hoặc đối tượng biến loại.

format có thể được sử dụng để kiểm soát định dạng trả về giá trị:

>>>   danh = không xác định
>>> call_evaluate_function( danh.evaluate_value, Format.VALUE)
Traceback (cuộc gọi gần đây nhất):
...
NameError: tên 'không xác định' không được xác định
>>> call_evaluate_function( danh.evaluate_value, Format.FORWARDREF)
ForwardRef('không xác định')
>>> call_evaluate_function( danh.evaluate_value, Format.STRING)
'không xác định'

Added in version 3.14.

annotationlib.get_annotate_from_class_namespace(namespace)

Truy xuất annotate function từ từ điển không gian tên lớp namespace. Trả về None nếu không gian tên không chứa chức năng chú thích. Điều này chủ yếu hữu ích trước khi lớp được tạo hoàn chỉnh (ví dụ: trong siêu dữ liệu); sau khi lớp tồn tại, chức năng chú thích có thể được truy xuất bằng cls.__annotate__. Xem below để biết ví dụ sử dụng hàm này trong siêu dữ liệu.

Added in version 3.14.

annotationlib.get_annotations(obj, *, globals=None, locals=None, eval_str=False, format=Format.VALUE)

Tính toán các chú thích cho một đối tượng.

obj có thể là một đối tượng có thể gọi, lớp, mô-đun hoặc đối tượng khác có thuộc tính __annotate__ hoặc __annotations__. Vượt qua bất kỳ đối tượng nào khác sẽ tăng TypeError.

Tham số format kiểm soát định dạng trả về các chú thích và phải là thành viên của enum Format hoặc số nguyên tương đương của nó. Các định dạng khác nhau hoạt động như sau:

  • VALUE: object.__annotations__ được thử trước; nếu điều đó không tồn tại, hàm object.__annotate__ sẽ được gọi nếu nó tồn tại.

  • FORWARDREF: Nếu object.__annotations__ tồn tại và có thể được đánh giá thành công thì nó sẽ được sử dụng; nếu không, hàm object.__annotate__ sẽ được gọi. Nếu nó cũng không tồn tại, object.__annotations__ sẽ được thử lại và mọi lỗi khi truy cập nó sẽ được khắc phục lại.

    • Khi gọi object.__annotate__, đầu tiên nó được gọi bằng FORWARDREF. Nếu điều này không được triển khai, thì nó sẽ kiểm tra xem VALUE_WITH_FAKE_GLOBALS có được hỗ trợ hay không và sử dụng nó trong môi trường toàn cầu giả. Nếu cả hai định dạng này đều không được hỗ trợ, nó sẽ quay lại sử dụng VALUE. Nếu VALUE không thành công, lỗi từ lệnh gọi này sẽ xuất hiện.

  • STRING: Nếu object.__annotate__ tồn tại, nó sẽ được gọi đầu tiên; mặt khác, object.__annotations__ được sử dụng và xâu chuỗi bằng annotations_to_string().

    • Khi gọi object.__annotate__, đầu tiên nó được gọi bằng STRING. Nếu điều này không được triển khai, thì nó sẽ kiểm tra xem VALUE_WITH_FAKE_GLOBALS có được hỗ trợ hay không và sử dụng nó trong môi trường toàn cầu giả. Nếu cả hai định dạng này đều không được hỗ trợ, nó sẽ quay lại sử dụng VALUE với kết quả được chuyển đổi bằng annotations_to_string(). Nếu VALUE không thành công, lỗi từ lệnh gọi này sẽ xuất hiện.

Trả về một lệnh. get_annotations() trả về một lệnh mới mỗi khi nó được gọi; gọi nó hai lần trên cùng một đối tượng sẽ trả về hai ký tự khác nhau nhưng tương đương.

Hàm này xử lý một số chi tiết cho bạn:

  • Nếu eval_str là đúng, các giá trị thuộc loại str sẽ không được xâu chuỗi bằng eval(). Điều này được thiết kế để sử dụng với các chú thích được xâu chuỗi (from __future__ import annotations). Sẽ có lỗi khi đặt eval_str thành true với các định dạng khác Format.VALUE.

  • Nếu obj không có lệnh chú thích, sẽ trả về một lệnh trống. (Các hàm và phương thức luôn có một chú thích; các lớp, mô-đun và các loại lệnh gọi khác có thể không có.)

  • Bỏ qua các chú thích được kế thừa trên các lớp cũng như các chú thích trên siêu dữ liệu. Nếu một lớp không có lệnh chú thích riêng, sẽ trả về một lệnh trống.

  • Tất cả quyền truy cập vào các thành viên đối tượng và giá trị dict đều được thực hiện bằng getattr()dict.get() để đảm bảo an toàn.

eval_str kiểm soát xem các giá trị của loại str có được thay thế bằng kết quả của việc gọi eval() trên các giá trị đó hay không:

  • Nếu eval_str là đúng, eval() được gọi trên các giá trị thuộc loại str. (Lưu ý rằng get_annotations() không bắt được ngoại lệ; nếu eval() đưa ra một ngoại lệ, nó sẽ giải phóng ngăn xếp vượt qua lệnh gọi get_annotations().)

  • Nếu eval_str là sai (mặc định), các giá trị của loại str sẽ không thay đổi.

globalslocals được chuyển vào eval(); xem tài liệu về eval() để biết thêm thông tin. Nếu globals hoặc localsNone, hàm này có thể thay thế giá trị đó bằng giá trị mặc định theo ngữ cảnh cụ thể, tùy thuộc vào type(obj):

  • Nếu obj là một mô-đun, globals mặc định là obj.__dict__.

  • Nếu obj là một lớp, globals mặc định là sys.modules[obj.__module__].__dict__locals mặc định là không gian tên lớp obj.

  • Nếu obj là một hàm có thể gọi được thì globals sẽ mặc định là obj.__globals__, mặc dù nếu obj là một hàm được gói (sử dụng functools.update_wrapper()) hoặc một đối tượng functools.partial, thì nó sẽ được mở gói cho đến khi tìm thấy một hàm không được gói.

Gọi get_annotations() là cách tốt nhất để truy cập vào chú thích của bất kỳ đối tượng nào. Xem Các phương pháp hay nhất về chú thích để biết thêm thông tin về các phương pháp hay nhất về chú thích.

>>> def f(a: int, b: str) -> float:
... vượt qua
>>> get_annotations(f)
{'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'float'>}

Added in version 3.14.

annotationlib.type_repr(value)

Chuyển đổi giá trị Python tùy ý sang định dạng phù hợp để sử dụng theo định dạng STRING. Điều này gọi repr() cho hầu hết các đối tượng, nhưng có cách xử lý đặc biệt đối với một số đối tượng, chẳng hạn như đối tượng loại.

Điều này có nghĩa là một trình trợ giúp cho các hàm chú thích do người dùng cung cấp hỗ trợ định dạng STRING nhưng không có quyền truy cập vào mã tạo chú thích. Nó cũng có thể được sử dụng để cung cấp cách biểu diễn chuỗi thân thiện với người dùng cho các đối tượng khác có chứa các giá trị thường gặp trong chú thích.

Added in version 3.14.

Công thức nấu ăn

Sử dụng chú thích trong siêu dữ liệu

Zz000zz có thể muốn kiểm tra hoặc thậm chí sửa đổi các chú thích trong nội dung lớp trong quá trình tạo lớp. Làm như vậy yêu cầu truy xuất các chú thích từ từ điển vùng tên lớp. Đối với các lớp được tạo bằng from __future__ import annotations, các chú thích sẽ nằm trong khóa __annotations__ của từ điển. Đối với các lớp khác có chú thích, get_annotate_from_class_namespace() có thể được sử dụng để lấy hàm chú thích và call_annotate_function() có thể được sử dụng để gọi và truy xuất chú thích. Sử dụng định dạng FORWARDREF thường sẽ là tốt nhất, vì điều này cho phép các chú thích tham chiếu đến những cái tên chưa thể giải quyết được khi lớp được tạo.

Để sửa đổi chú thích, cách tốt nhất là tạo hàm chú thích trình bao bọc gọi hàm chú thích ban đầu, thực hiện mọi điều chỉnh cần thiết và trả về kết quả.

Dưới đây là ví dụ về siêu dữ liệu lọc tất cả các chú thích typing.ClassVar khỏi lớp và đặt chúng vào một thuộc tính riêng biệt:

nhập chú thíchlib
nhập 

lớp ClassVarSeparator(loại):
   def __new__(mcls, tên, căn cứ, ns):
      nếu "__annotations__" trong ns: # from __future__ nhập chú thích
         chú thích = ns["__annotations__"]
         classvar_keys = {
            khóa cho khóa, giá trị trong chú thích.items()
            so sánh chuỗi # Use để đơn giản; một giải pháp mạnh mẽ hơn
            # could sử dụng chú thíchlib.ForwardRef.evaluate
            if value.startswith("ClassVar")
         }
         classvars = {key: chú thích[key] cho khóa trong classvar_keys}
         ns["__annotations__"] = {
            key: giá trị cho khóa, giá trị trong chú thích.items()
            nếu khóa không  trong classvar_keys
         }
         bọc_annotate = Không 
      elif chú thích := chú thíchlib.get_annotate_from_class_namespace(ns):
         chú thích = chú thíchlib.call_annotate_function(
            chú thích, định dạng=annotationlib.Format.FORWARDREF
         )
         classvar_keys = {
            khóa cho khóa, giá trị trong chú thích.items()
            nếu đang .get_origin(value) đang .ClassVar
         }
         classvars = {key: chú thích[key] cho khóa trong classvar_keys}

         def được bọc_annotate (định dạng):
            annos = chú thíchlib.call_annotate_function(chú thích, định dạng, chủ sở hữu=typ)
            trả về {key: giá trị cho khóa, giá trị trong annos.items() nếu khóa không  trong classvar_keys}

      khác: chú thích # no
         lớpvars = {}
         bọc_annotate = Không 
      typ = super().__new__(mcls, tên, căn cứ, ns)

      nếu Wrap_annotate không phải  Không :
         # Wrap __annotate__ ban đầu có trình bao bọc loại bỏ ClassVars
         typ.__annotate__ = bọc_annotate
      typ.classvars = classvars # Store các ClassVars trong một thuộc tính riêng biệt
      kiểu trả về

Hạn chế của định dạng STRING

Định dạng STRING nhằm mục đích gần đúng mã nguồn của chú thích, nhưng chiến lược triển khai được sử dụng có nghĩa là không phải lúc nào cũng có thể khôi phục mã nguồn chính xác.

Đầu tiên, trình xâu chuỗi tất nhiên không thể khôi phục bất kỳ thông tin nào không có trong mã được biên dịch, bao gồm các nhận xét, khoảng trắng, dấu ngoặc đơn và các thao tác được trình biên dịch đơn giản hóa.

Thứ hai, trình tạo chuỗi có thể chặn hầu hết tất cả các hoạt động liên quan đến tên được tra cứu trong một phạm vi nào đó, nhưng nó không thể chặn các hoạt động hoạt động hoàn toàn trên các hằng số. Hệ quả tất yếu là điều này cũng có nghĩa là sẽ không an toàn khi yêu cầu định dạng STRING trên mã không đáng tin cậy: Python đủ mạnh để có thể thực thi mã tùy ý ngay cả khi không có quyền truy cập vào bất kỳ toàn cục hoặc nội dung nào. Ví dụ:

>>> def f(x: (1).__class__.__base__.__subclasses__()[-1].__init__.__buildins__["print"]("Xin chào thế giới")): vượt qua
...
>>> chú thíchlib.get_annotations(f, format=annotationlib.Format.STRING)
Xin chào thế giới
{'x': 'Không có'}

Ghi chú

Ví dụ cụ thể này hoạt động tại thời điểm viết bài, nhưng nó phụ thuộc vào chi tiết triển khai và không được đảm bảo sẽ hoạt động trong tương lai.

Trong số các loại biểu thức khác nhau tồn tại trong Python, được biểu thị bằng mô-đun ast, một số biểu thức được hỗ trợ, nghĩa là định dạng STRING thường có thể khôi phục mã nguồn gốc; những cái khác không được hỗ trợ, có nghĩa là chúng có thể dẫn đến kết quả đầu ra không chính xác hoặc bị lỗi.

Những điều sau đây được hỗ trợ (đôi khi có cảnh báo):

Các mục sau đây không được hỗ trợ nhưng sẽ đưa ra lỗi thông tin khi trình tạo chuỗi gặp phải:

  • ast.FormattedValue (chuỗi f; không phát hiện được lỗi nếu sử dụng các công cụ xác định chuyển đổi như !r)

  • ast.JoinedStr (dây f)

Các mục sau không được hỗ trợ và dẫn đến kết quả đầu ra không chính xác:

Những điều sau đây không được phép trong phạm vi chú thích và do đó không liên quan:

Hạn chế của định dạng FORWARDREF

Định dạng FORWARDREF nhằm mục đích tạo ra nhiều giá trị thực nhất có thể, với mọi thứ không thể giải quyết được sẽ được thay thế bằng đối tượng ForwardRef. Nó bị ảnh hưởng bởi các Hạn chế tương tự như định dạng STRING: các chú thích thực hiện các thao tác trên chữ hoặc sử dụng các loại biểu thức không được hỗ trợ có thể đưa ra các ngoại lệ khi được đánh giá bằng định dạng FORWARDREF.

Dưới đây là một số ví dụ về hành vi với các biểu thức không được hỗ trợ:

>>> từ nhập chú thíchlib get_annotations, Định dạng
>>> def zerodiv(x: 1 / 0): ...
>>> get_annotations(zerodiv, format=Format.STRING)
Traceback (cuộc gọi gần đây nhất):
  ...
ZeroDivisionError: chia cho 0
>>> get_annotations(zerodiv, format=Format.FORWARDREF)
Traceback (cuộc gọi gần đây nhất):
  ...
ZeroDivisionError: chia cho 0
>>> def ifexp(x: 1 if y else 0): ...
>>> get_annotations(ifexp, format=Format.STRING)
{'x': '1'}

Ý nghĩa bảo mật của các chú thích nội tâm

Phần lớn chức năng trong mô-đun này liên quan đến việc thực thi mã liên quan đến chú thích, sau đó có thể thực hiện những việc tùy ý. Ví dụ: get_annotations() có thể gọi annotate function tùy ý và ForwardRef.evaluate() có thể gọi eval() trên một chuỗi tùy ý. Mã chứa trong chú thích có thể thực hiện các lệnh gọi hệ thống tùy ý, nhập vòng lặp vô hạn hoặc thực hiện bất kỳ thao tác nào khác. Điều này cũng đúng đối với mọi quyền truy cập vào thuộc tính __annotations__ và đối với các chức năng khác nhau trong mô-đun typing hoạt động với các chú thích, chẳng hạn như typing.get_type_hints().

Bất kỳ vấn đề bảo mật nào phát sinh từ việc này cũng áp dụng ngay sau khi nhập mã có thể chứa các chú thích không đáng tin cậy: việc nhập mã luôn có thể khiến các hoạt động tùy ý được thực hiện. Tuy nhiên, sẽ không an toàn khi chấp nhận chuỗi hoặc dữ liệu đầu vào khác từ nguồn không đáng tin cậy và chuyển chúng tới bất kỳ API nào để xem xét chú thích, chẳng hạn như bằng cách chỉnh sửa từ điển __annotations__ hoặc trực tiếp tạo đối tượng ForwardRef.