GeezerVison is showing python.github.io — typing --- پشتیبانی از راهنماهای نوع
typing --- پشتیبانی از راهنماهای نوع¶
کد منبع: Lib/typing.py
نکته
رانتایم پایتون حاشیهنویسیهای نوع توابع و متغیرها را اعمال نمیکند. این حاشیهنویسیها میتوانند توسط ابزارهای شخص ثالث مانند بررسیکنندههای نوع، IDEها، لینترها و غیره مورد استفاده قرار گیرند.
این ماژول پشتیبانی در رانتایم برای راهنماهای نوع را فراهم میکند.
تابع زیر را در نظر بگیرید:
def surface_area_of_cube(edge_length: float) -> str:
return f"The surface area of the cube is {6 * edge_length ** 2}."
تابع surface_area_of_cube یک آرگومان میگیرد که انتظار میرود نمونهای از float باشد، همانطور که type hint edge_length: float نشان میدهد. انتظار میرود تابع نمونهای از str را برگرداند، همانطور که اشاره -> str نشان میدهد.
اگرچه راهنماهای نوع میتوانند کلاسهای سادهای مانند float یا str باشند، اما میتوانند پیچیدهتر نیز باشند. ماژول typing واژگانی از راهنماهای نوع پیشرفتهتر را فراهم میکند.
قابلیتهای جدید اغلب به ماژول typing اضافه میشوند. بسته typing_extensions بکپورتهایی (backports) از این قابلیتهای جدید را به نسخههای قدیمیتر پایتون ارائه میدهد.
همچنین ببینید
- برگه تقلب نوعدهی (Typing)
مروری سریع بر راهنماهای نوع (میزبانیشده در مستندات mypy)
- بخش Type System Reference از مستندات mypy
سیستم نوعدهی پایتون از طریق PEPها استاندارد شده است، بنابراین این مرجع باید بهطور گسترده برای بیشتر بررسیکنندههای نوع پایتون صدق کند. (برخی بخشها ممکن است همچنان مختص mypy باشند.)
- نوعدهی ایستا با پایتون
مستندات مستقل از بررسیکننده نوع که توسط کامیونیتی نوشته شده است و ویژگیهای سیستم نوع، ابزارهای مفید مرتبط با نوعدهی و بهترین شیوههای نوعدهی را با جزئیات شرح میدهد.
نامهای مستعار نوع¶
یک ناممستعار نوع با استفاده از دستور type تعریف میشود، که یک نمونه از TypeAliasType را ایجاد میکند. در این مثال، از نظر بررسیکنندههای نوع ایستا، Vector و list[float] معادل یکدیگر در نظر گرفته میشوند:
type Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# passes type checking; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])
نامهای مستعار نوع برای سادهسازی امضاهای نوع پیچیده مفید هستند. برای مثال:
from collections.abc import Sequence
type ConnectionOptions = dict[str, str]
type Address = tuple[str, int]
type Server = tuple[Address, ConnectionOptions]
def broadcast_message(message: str, servers: Sequence[Server]) -> None:
...
# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
message: str,
servers: Sequence[tuple[tuple[str, int], dict[str, str]]]
) -> None:
...
دستور type در پایتون 3.12 جدید است. برای سازگاری با نسخههای پیشین، میتوان نامهای مستعار نوع را نیز از طریق انتساب ساده ایجاد کرد:
یا با TypeAlias علامتگذاری شود تا بهصراحت مشخص شود که این یک نام مستعار نوع است، نه یک انتساب متغیر معمولی:
from typing import TypeAlias
Vector: TypeAlias = list[float]
NewType¶
برای ایجاد انواع متمایز، از کمکی NewType استفاده کنید:
from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)
بررسیگر نوع ایستا با نوع جدید بهگونهای رفتار میکند که گویی زیرکلاسی از نوع اصلی است. این برای کمک به شناسایی خطاهای منطقی مفید است:
def get_user_name(user_id: UserId) -> str:
...
# passes type checking
user_a = get_user_name(UserId(42351))
# fails type checking; an int is not a UserId
user_b = get_user_name(-1)
شما همچنان میتوانید تمام عملیاتهای int را روی متغیری از نوع UserId انجام دهید، اما نتیجه همیشه از نوع int خواهد بود. این امکان را به شما میدهد که هر جا که ممکن است یک int مورد انتظار باشد، یک UserId را ارسال کنید، اما از ایجاد اشتباهی یک UserId بهصورت نامعتبر جلوگیری میکند:
# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)
توجه داشته باشید که این بررسیها فقط توسط بررسیکننده نوع ایستا اعمال میشوند. در رانتایم، دستور Derived = NewType('Derived', Base)، Derived را به یک شیء فراخوانیپذیر تبدیل میکند که بلافاصله هر پارامتری را که به آن بدهید برمیگرداند. این بدان معناست که عبارت Derived(some_value) کلاس جدیدی ایجاد نمیکند و سربار زیادی فراتر از یک فراخوانی تابع معمولی به همراه ندارد.
بهطور دقیقتر، عبارت some_value is Derived(some_value) همیشه در رانتایم درست است.
ایجاد یک زیرنوع از Derived نامعتبر است:
from typing import NewType
UserId = NewType('UserId', int)
# Fails at runtime and does not pass type checking
class AdminUserId(UserId): pass
با این حال، امکان ایجاد یک NewType بر پایهی یک NewType «مشتقشده» وجود دارد:
from typing import NewType
UserId = NewType('UserId', int)
ProUserId = NewType('ProUserId', UserId)
و بررسی نوع برای ProUserId مطابق انتظار کار خواهد کرد.
برای جزئیات بیشتر PEP 484 را ببینید.
نکته
به یاد داشته باشید که استفاده از یک نام مستعار نوع، دو نوع را معادل یکدیگر اعلام میکند. انجام type Alias = Original باعث میشود بررسیکننده نوع ایستا، Alias را در همه موارد دقیقاً معادل Original در نظر بگیرد. این زمانی مفید است که بخواهید امضاهای نوع پیچیده را سادهتر کنید.
در مقابل، NewType یک نوع را زیرنوع نوع دیگری اعلام میکند. انجام Derived = NewType('Derived', Original) باعث میشود بررسیگر نوع ایستا با Derived بهعنوان زیرکلاس Original رفتار کند، که به این معناست که نمیتوان از مقداری از نوع Original در مواردی استفاده کرد که مقداری از نوع Derived مورد انتظار است. این موضوع زمانی مفید است که بخواهید از خطاهای منطقی با کمترین هزینهی رانتایم جلوگیری کنید.
اضافه شده در نسخهی 3.5.2.
تغییر یافته در نسخهی 3.10: NewType اکنون یک کلاس است، نه یک تابع. در نتیجه، هنگام فراخوانی NewType نسبت به یک تابع معمولی، مقداری هزینهی رانتایم اضافی وجود دارد.
تغییر یافته در نسخهی 3.11: عملکرد فراخوانی NewType به سطح آن در Python 3.9 بازگردانده شده است.
حاشیهنویسی اشیاء فراخوانیپذیر¶
توابع — یا دیگر اشیاء callable — میتوانند با collections.abc.Callable یا typing.Callable منسوخ حاشیهنویسی شوند. Callable[[int], str] نشاندهنده تابعی است که تنها یک پارامتر از نوع int میگیرد و یک str برمیگرداند.
برای مثال:
from collections.abc import Callable, Awaitable
def feeder(get_next_item: Callable[[], str]) -> None:
... # Body
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
... # Body
async def on_update(value: str) -> None:
... # Body
callback: Callable[[str], Awaitable[None]] = on_update
نحوِ زیرنویسی (subscription) باید همواره دقیقاً با دو مقدار استفاده شود: فهرست آرگومانها و نوع بازگشتی. فهرست آرگومانها باید فهرستی از انواع، یک ParamSpec، Concatenate، یا یک سهنقطه (...) باشد. نوع بازگشتی باید یک نوع واحد باشد.
اگر یک سهنقطه (ellipsis) بهصورت ... بهعنوان فهرست آرگومانها داده شود، نشان میدهد که یک فراخوانیپذیر با هر فهرست پارامتر دلخواهی قابلقبول است:
def concat(x: str, y: str) -> str:
return x + y
x: Callable[..., str]
x = str # OK
x = concat # Also OK
Callable نمیتواند امضاهای پیچیده را بیان کند، مانند توابعی که تعداد متغیری از آرگومانها را میپذیرند، توابع سربارگذاریشده (overloaded)، یا توابعی که پارامترهای فقط کلیدواژهای دارند. با این حال، این امضاها را میتوان با تعریف یک کلاس Protocol با متد __call__() بیان کرد:
from collections.abc import Iterable
from typing import Protocol
class Combiner(Protocol):
def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ...
def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes:
for item in data:
...
def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]:
...
def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]:
...
batch_proc([], good_cb) # OK
batch_proc([], bad_cb) # Error! Argument 2 has incompatible type because of
# different name and kind in the callback
فراخوانیپذیرهایی که فراخوانیپذیرهای دیگر را بهعنوان آرگومان میپذیرند، میتوانند با استفاده از ParamSpec نشان دهند که نوع پارامترهایشان به یکدیگر وابسته است. علاوه بر این، اگر آن فراخوانیپذیر آرگومانهایی را به فراخوانیپذیرهای دیگر اضافه کند یا از آنها حذف کند، میتوان از عملگر Concatenate استفاده کرد. آنها بهترتیب به شکل Callable[ParamSpecVariable, ReturnType] و Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType] هستند.
همچنین ببینید
مستندات مربوط به ParamSpec و Concatenate نمونههایی از کاربرد در Callable ارائه میدهد.
عامها¶
از آنجا که اطلاعات نوعِ شیءهای نگهداریشده در ظرفها را نمیتوان بهصورت ایستا و به شکلی عام استنتاج کرد، بسیاری از کلاسهای ظرف در کتابخانهی استاندارد از زیرنویسی پشتیبانی میکنند تا انواع مورد انتظار عناصر ظرف را مشخص کنند.
from collections.abc import Mapping, Sequence
class Employee: ...
# Sequence[Employee] indicates that all elements in the sequence
# must be instances of "Employee".
# Mapping[str, str] indicates that all keys and all values in the mapping
# must be strings.
def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None: ...
توابع عام و کلاسها را میتوان با استفاده از سینتکس پارامتر نوع پارامتریزه کرد:
from collections.abc import Sequence
def first[T](l: Sequence[T]) -> T: # Function is generic over the TypeVar "T"
return l[0]
یا با استفادهی مستقیم از کارخانهی TypeVar:
from collections.abc import Sequence
from typing import TypeVar
U = TypeVar('U') # Declare type variable "U"
def second(l: Sequence[U]) -> U: # Function is generic over the TypeVar "U"
return l[1]
تغییر یافته در نسخهی 3.12: پشتیبانی سینتکسی از ژنریکها (generics) در پایتون 3.12 جدید است.
حاشیهنویسی تاپلها¶
برای بیشتر ظرفها در پایتون، سیستم نوعدهی فرض میکند که تمام عناصر داخل ظرف از یک نوع باشند. برای مثال:
from collections.abc import Mapping
# Type checker will infer that all elements in ``x`` are meant to be ints
x: list[int] = []
# Type checker error: ``list`` only accepts a single type argument:
y: list[int, str] = [1, 'foo']
# Type checker will infer that all keys in ``z`` are meant to be strings,
# and that all values in ``z`` are meant to be either strings or ints
z: Mapping[str, str | int] = {}
list تنها یک آرگومان نوعی را میپذیرد، بنابراین یک بررسیگر نوع برای انتساب y در بالا خطایی را نشان میدهد. به همین ترتیب، Mapping تنها دو آرگومان نوعی را میپذیرد: اولی نوع کلیدها و دومی نوع مقادیر را نشان میدهد.
با این حال، برخلاف بیشتر ظرفهای دیگر پایتون، در کد پایتون مصطلح رایج است که تاپلها عناصری داشته باشند که همهی آنها از یک نوع نیستند. به همین دلیل، تاپلها در سامانهی نوعدهی پایتون حالت خاصی دارند. tuple هر تعداد آرگومان نوع را میپذیرد:
# OK: ``x`` is assigned to a tuple of length 1 where the sole element is an int
x: tuple[int] = (5,)
# OK: ``y`` is assigned to a tuple of length 2;
# element 1 is an int, element 2 is a str
y: tuple[int, str] = (5, "foo")
# Error: the type annotation indicates a tuple of length 1,
# but ``z`` has been assigned to a tuple of length 3
z: tuple[int] = (1, 2, 3)
برای نشان دادن یک تاپل که میتواند هر طولی داشته باشد و همهی عناصر آن از نوع یکسان T باشند، از سهنقطهی لفظی (ellipsis) ... استفاده کنید: tuple[T, ...]. برای نشان دادن یک تاپل خالی، از tuple[()] استفاده کنید. استفاده از tuple ساده بهعنوان حاشیهنویسی معادل استفاده از tuple[Any, ...] است:
x: tuple[int, ...] = (1, 2)
# These reassignments are OK: ``tuple[int, ...]`` indicates x can be of any length
x = (1, 2, 3)
x = ()
# This reassignment is an error: all elements in ``x`` must be ints
x = ("foo", "bar")
# ``y`` can only ever be assigned to an empty tuple
y: tuple[()] = ()
z: tuple = ("foo", "bar")
# These reassignments are OK: plain ``tuple`` is equivalent to ``tuple[Any, ...]``
z = (1, 2, 3)
z = ()
نوع اشیای کلاس¶
متغیری که با C حاشیهنویسیشده است میتواند مقداری از نوع C را بپذیرد. در مقابل، متغیری که با type[C] (یا typing.Type[C] منسوخ) حاشیهنویسیشده است میتواند مقادیری را بپذیرد که خودشان کلاس هستند — بهطور مشخص، شیء کلاس C را خواهد پذیرفت. برای مثال:
a = 3 # Has type ``int``
b = int # Has type ``type[int]``
c = type(a) # Also has type ``type[int]``
توجه داشته باشید که type[C] هموردا (covariant) است:
class User: ...
class ProUser(User): ...
class TeamUser(User): ...
def make_new_user(user_class: type[User]) -> User:
# ...
return user_class()
make_new_user(User) # OK
make_new_user(ProUser) # Also OK: ``type[ProUser]`` is a subtype of ``type[User]``
make_new_user(TeamUser) # Still fine
make_new_user(User()) # Error: expected ``type[User]`` but got ``User``
make_new_user(int) # Error: ``type[int]`` is not a subtype of ``type[User]``
تنها پارامترهای مجاز برای type عبارتاند از کلاسها، Any، type variables و اجتماعهایی از هر یک از این انواع. برای مثال:
def new_non_team_user(user_class: type[BasicUser | ProUser]): ...
new_non_team_user(BasicUser) # OK
new_non_team_user(ProUser) # OK
new_non_team_user(TeamUser) # Error: ``type[TeamUser]`` is not a subtype
# of ``type[BasicUser | ProUser]``
new_non_team_user(User) # Also an error
type[Any] معادل type است که ریشهی سلسلهمراتب فراکلاسها در پایتون است.
حاشیهنویسی تولیدگرها و همروالها¶
یک تولیدگر میتواند با استفاده از نوع عام Generator[YieldType, SendType, ReturnType] حاشیهنویسی شود. برای مثال:
def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'
توجه داشته باشید که برخلاف بسیاری دیگر از کلاسهای عام در کتابخانه استاندارد، SendTypeِ Generator رفتار پادوردا (contravariantly) دارد، نه هموردا (covariantly) یا ناوردا (invariantly).
مقدار پیشفرض پارامترهای SendType و ReturnType برابر با None است:
def infinite_stream(start: int) -> Generator[int]:
while True:
yield start
start += 1
همچنین امکان تنظیم این نوعها بهصورت صریح وجود دارد:
def infinite_stream(start: int) -> Generator[int, None, None]:
while True:
yield start
start += 1
تولیدگرهای سادهای که تنها مقادیر را yield میکنند، همچنین میتوانند بهعنوان داشتن نوع بازگشت Iterable[YieldType] یا Iterator[YieldType] حاشیهنویسی شوند:
def infinite_stream(start: int) -> Iterator[int]:
while True:
yield start
start += 1
تولیدگرهای ناهمگام به شیوهای مشابه مدیریت میشوند، اما انتظار آرگومان نوع ReturnType را نداشته باشید (AsyncGenerator[YieldType, SendType]). آرگومان SendType بهطور پیشفرض None است، بنابراین تعاریف زیر معادل هستند:
async def infinite_stream(start: int) -> AsyncGenerator[int]:
while True:
yield start
start = await increment(start)
async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
while True:
yield start
start = await increment(start)
مانند حالت همگام، AsyncIterable[YieldType] و AsyncIterator[YieldType] نیز در دسترس هستند:
async def infinite_stream(start: int) -> AsyncIterator[int]:
while True:
yield start
start = await increment(start)
همروالها را میتوان با استفاده از Coroutine[YieldType, SendType, ReturnType] حاشیهنویسی کرد. آرگومانهای عام متناظر با آرگومانهای Generator هستند، برای مثال:
from collections.abc import Coroutine
c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere
x = c.send('hi') # Inferred type of 'x' is list[str]
async def bar() -> None:
y = await c # Inferred type of 'y' is int
انواع عام تعریفشده توسط کاربر¶
یک کلاس تعریفشده توسط کاربر میتواند بهعنوان یک کلاس عام تعریف شود.
from logging import Logger
class LoggedVar[T]:
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
این سینتکس نشان میدهد که کلاس LoggedVar با یک متغیر نوع واحد T پارامتریزهشده است. این موضوع همچنین T را بهعنوان یک نوع در بدنه کلاس معتبر میسازد.
کلاسهای عام بهطور ضمنی از Generic ارث میبرند. برای سازگاری با Python 3.11 و پایینتر، همچنین میتوان بهطور صریح از Generic ارث برد تا یک کلاس عام مشخص شود:
from typing import TypeVar, Generic
T = TypeVar('T')
class LoggedVar(Generic[T]):
...
کلاسهای عام دارای متد __class_getitem__() هستند، به این معنا که میتوانند در رانتایم پارامتریزه شوند (مثلاً LoggedVar[int] در زیر):
from collections.abc import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
یک نوع عام میتواند هر تعدادی از متغیرهای نوع داشته باشد. تمام گونههای TypeVar بهعنوان پارامتر برای یک نوع عام مجاز هستند:
from typing import TypeVar, Generic, Sequence
class WeirdTrio[T, B: Sequence[bytes], S: (int, str)]:
...
OldT = TypeVar('OldT', contravariant=True)
OldB = TypeVar('OldB', bound=Sequence[bytes], covariant=True)
OldS = TypeVar('OldS', int, str)
class OldWeirdTrio(Generic[OldT, OldB, OldS]):
...
هر آرگومان متغیر نوع برای Generic باید متمایز باشد. بنابراین این نامعتبر است:
from typing import TypeVar, Generic
...
class Pair[M, M]: # SyntaxError
...
T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID
...
کلاسهای عام میتوانند از کلاسهای دیگر نیز ارثبری کنند:
from collections.abc import Sized
class LinkedList[T](Sized):
...
هنگام ارثبری از کلاسهای عام، برخی پارامترهای نوع میتوانند ثابت باشند:
from collections.abc import Mapping
class MyDict[T](Mapping[str, T]):
...
در این حالت MyDict تنها یک پارامتر دارد، T.
استفاده از یک کلاس عام بدون مشخص کردن پارامترهای نوع، برای هر جایگاه Any را فرض میکند. در مثال زیر، MyIterable عام نیست، اما بهطور ضمنی از Iterable[Any] ارث میبرد:
from collections.abc import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
...
نامهای مستعار نوع عام تعریفشده توسط کاربر نیز پشتیبانی میشوند. مثالها:
from collections.abc import Iterable
type Response[S] = Iterable[S] | int
# Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]:
...
type Vec[T] = Iterable[tuple[T, T]]
def inproduct[T: (int, float, complex)](v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
return sum(x*y for x, y in v)
برای سازگاری با عقبگرد، نامهای مستعار نوع عام را همچنین میتوان از طریق یک انتساب ساده ایجاد کرد:
from collections.abc import Iterable
from typing import TypeVar
S = TypeVar("S")
Response = Iterable[S] | int
تغییر یافته در نسخهی 3.7: Generic دیگر فراکلاس سفارشی ندارد.
تغییر یافته در نسخهی 3.12: پشتیبانی نحوی از عامسازی و نامهای مستعار نوع در نسخه 3.12 جدید است. پیش از این، کلاسهای عام باید بهصراحت از Generic ارثبری میکردند یا حاوی یک متغیر نوع در یکی از پایههای خود بودند.
عامهای تعریفشده توسط کاربر برای عبارات پارامتر نیز از طریق متغیرهای مشخصهی پارامتر در قالب [**P] پشتیبانی میشوند. این رفتار با رفتار متغیرهای نوع که در بالا توصیف شد، سازگار است، زیرا متغیرهای مشخصهی پارامتر توسط ماژول typing بهعنوان یک متغیر نوع تخصصی در نظر گرفته میشوند. تنها استثنا نسبت به این مورد این است که میتوان از فهرستی از انواع برای جایگزینی یک ParamSpec استفاده کرد:
>>> class Z[T, **P]: ... # T is a TypeVar; P is a ParamSpec
...
>>> Z[int, [dict, float]]
__main__.Z[int, [dict, float]]
کلاسهای عام روی یک ParamSpec را میتوان با ارثبری صریح از Generic نیز ایجاد کرد. در این حالت، از ** استفاده نمیشود:
from typing import ParamSpec, Generic
P = ParamSpec('P')
class Z(Generic[P]):
...
تفاوت دیگر بین TypeVar و ParamSpec این است که یک نوع عام با تنها یک متغیر مشخصکنندهی پارامتر، به دلایل زیبایی فهرستهای پارامتر را در قالبهای X[[Type1, Type2, ...]] و همچنین X[Type1, Type2, ...] میپذیرد. بهصورت داخلی، دومی به اولی تبدیل میشود، بنابراین موارد زیر معادل هستند:
>>> class X[**P]: ...
...
>>> X[int, str]
__main__.X[[int, str]]
>>> X[[int, str]]
__main__.X[[int, str]]
توجه داشته باشید که انواع عام با ParamSpec ممکن است در برخی موارد پس از جایگزینی، __parameters__ درستی نداشته باشند، زیرا عمدتاً برای بررسی ایستای نوع در نظر گرفته شدهاند.
تغییر یافته در نسخهی 3.10: اکنون میتوان Generic را روی عبارتهای پارامتری پارامتریزه کرد. برای جزئیات بیشتر، ParamSpec و PEP 612 را ببینید.
یک کلاس عام تعریفشده توسط کاربر میتواند ABCها را بهعنوان کلاسهای پایه داشته باشد، بدون آنکه تعارض فراکلاس رخ دهد. فراکلاسهای عام پشتیبانی نمیشوند. نتیجهی پارامترسازی عامها در نهانگاه ذخیره میشود، و بیشتر انواع در ماژول typing، hashable و قابل مقایسه از نظر برابری هستند.
Any گونهای خاص از نوع است. یک بررسیگر نوع ایستا، هر نوعی را قابل انتساب به Any و Any را قابل انتساب به هر نوعی در نظر میگیرد.
این بدان معناست که میتوان هر عملیات یا فراخوانی متد را روی مقداری از نوع Any انجام داد و آن را به هر متغیری انتساب داد:
from typing import Any
a: Any = None
a = [] # OK
a = 2 # OK
s: str = ''
s = a # OK
def foo(item: Any) -> int:
# Passes type checking; 'item' could be any type,
# and that type might have a 'bar' method
item.bar()
...
توجه کنید که هنگام انتساب یک مقدار از نوع Any به یک نوع دقیقتر، هیچ بررسی نوعی انجام نمیشود. برای مثال، بررسیکننده نوع ایستا هنگام انتساب a به s خطایی گزارش نکرد، با وجود اینکه s از نوع str اعلام شده بود و در رانتایم یک مقدار int دریافت میکند!
علاوه بر این، همه توابع بدون نوع بازگشتی یا انواع پارامترها، بهطور ضمنی بهصورت پیشفرض از Any استفاده خواهند کرد:
def legacy_parser(text):
...
return data
# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
...
return data
این رفتار به شما اجازه میدهد زمانی که نیاز دارید کد با نوعدهی پویا را با کد با نوعدهی ایستا ترکیب کنید، از Any بهعنوان یک راه فرار استفاده کنید.
رفتار Any را با رفتار object مقایسه کنید. مشابه Any، هر نوعی زیرنوعی از object است. با این حال، برخلاف Any، عکس آن درست نیست: object زیرنوع هر نوع دیگری نیست.
این بدان معناست که وقتی نوع یک مقدار object باشد، بررسیگر نوع تقریباً تمام عملیات روی آن را رد میکند و انتساب آن به یک متغیر (یا استفاده از آن بهعنوان مقدار بازگشتی) از نوعی تخصصیتر، خطای نوع است. برای مثال:
def hash_a(item: object) -> int:
# Fails type checking; an object does not have a 'magic' method.
item.magic()
...
def hash_b(item: Any) -> int:
# Passes type checking
item.magic()
...
# Passes type checking, since ints and strs are subclasses of object
hash_a(42)
hash_a("foo")
# Passes type checking, since Any is assignable to all types
hash_b(42)
hash_b("foo")
از object برای نشان دادن اینکه یک مقدار میتواند بهصورت ایمن از نظر نوع (typesafe) هر نوعی باشد، استفاده کنید. از Any برای نشان دادن اینکه یک مقدار دارای نوعدهی پویا است، استفاده کنید.
زیرنوعدهی اسمی در مقابل ساختاری¶
در ابتدا PEP 484 سیستم نوع ایستای پایتون را بهگونهای تعریف کرد که از زیرنوعدهی اسمی (nominal subtyping) استفاده میکند. این بدان معناست که کلاس A در هر جا که کلاس B انتظار میرود، اگر و فقط اگر A زیرکلاسی از B باشد، مجاز است.
این الزام پیشتر در مورد کلاسهای پایه انتزاعی، مانند Iterable نیز اعمال میشد. مشکل این رویکرد آن است که یک کلاس باید بهصراحت برای پشتیبانی از آنها علامتگذاری میشد، که غیرپایتونی است و برخلاف کاری است که معمولاً در کد پایتون ایدئوماتیک با نوعدهی پویا انجام میشود. برای مثال، این مورد با PEP 484 مطابقت دارد:
from collections.abc import Sized, Iterable, Iterator
class Bucket(Sized, Iterable[int]):
...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[int]: ...
PEP 544 این مشکل را با امکان دادن به کاربران برای نوشتن کد بالا بدون کلاسهای پایه صریح در تعریف کلاس حل میکند و اجازه میدهد که Bucket توسط بررسیکنندههای نوع ایستا بهطور ضمنی یک زیرنوع از هر دو Sized و Iterable[int] در نظر گرفته شود. این بهعنوان زیرنوعدهی ساختاری (یا نوعدهی اردکی ایستا) شناخته میشود:
from collections.abc import Iterator, Iterable
class Bucket: # Note: no base classes
...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[int]: ...
def collect(items: Iterable[int]) -> int: ...
result = collect(Bucket()) # Passes type check
علاوه بر این، کاربر میتواند با زیرکلاسسازی از کلاس خاص Protocol، پروتکلهای سفارشی جدیدی تعریف کند تا بهطور کامل از زیرنوعدهی ساختاری (structural subtyping) بهرهمند شود (به مثالهای زیر مراجعه کنید).
محتویات ماژول¶
ماژول typing کلاسها، توابع و دکوراتورهای زیر را تعریف میکند.
اولیههای ویژه تایپ¶
انواع خاص¶
میتوان از این موارد بهعنوان نوعها در حاشیهنویسیها استفاده کرد. آنها از زیرنویسی با استفاده از [] پشتیبانی نمیکنند.
-
typing.Any¶
نوع خاصی که نشاندهندهی یک نوع بدون محدودیت است.
تغییر یافته در نسخهی 3.11: اکنون میتوان از Any بهعنوان کلاس پایه استفاده کرد. این میتواند برای اجتناب از خطاهای بررسیکننده نوع در کلاسهایی که میتوانند در هر جایی نوعدهی اردکی شوند یا بسیار پویا هستند، مفید باشد.
-
typing.AnyStr¶
یک متغیر نوع محدودشده.
تعریف:
AnyStr = TypeVar('AnyStr', str, bytes)
AnyStr برای استفاده در توابعی در نظر گرفته شده است که ممکن است آرگومانهای str یا bytes را بپذیرند، اما نمیتوانند اجازه دهند این دو با هم ترکیب شوند.
برای مثال:
def concat(a: AnyStr, b: AnyStr) -> AnyStr:
return a + b
concat("foo", "bar") # OK, output has type 'str'
concat(b"foo", b"bar") # OK, output has type 'bytes'
concat("foo", b"bar") # Error, cannot mix str and bytes
توجه داشته باشید که AnyStr، علیرغم نامش، هیچ ارتباطی با نوع Any ندارد و به معنای «هر رشتهای» نیز نیست. بهطور خاص، AnyStr و str | bytes با یکدیگر متفاوت هستند و موارد استفاده متفاوتی دارند:
# Invalid use of AnyStr:
# The type variable is used only once in the function signature,
# so cannot be "solved" by the type checker
def greet_bad(cond: bool) -> AnyStr:
return "hi there!" if cond else b"greetings!"
# The better way of annotating this function:
def greet_proper(cond: bool) -> str | bytes:
return "hi there!" if cond else b"greetings!"
منسوخ شده از نسخهی 3.13, در نسخهی 3.18 حذف خواهد شد: به نفع سینتکس پارامتر نوع جدید منسوخ شده است. بهجای ایمپورت کردن AnyStr، از class A[T: (str, bytes)]: ... استفاده کنید. برای جزئیات بیشتر، PEP 695 را ببینید.
در پایتون 3.16، AnyStr از typing.__all__ حذف خواهد شد و در رانتایم، هنگام دسترسی به آن یا ایمپورت آن از typing، هشدارهای از رده خارج شدن نشان داده خواهند شد. AnyStr در پایتون 3.18 از typing حذف خواهد شد.
-
typing.LiteralString¶
نوع خاصی که فقط شامل رشتههای لفظی است.
هر لفظی رشتهای با LiteralString سازگار است، همانطور که یک LiteralString دیگر نیز چنین است. با این حال، شیءای که فقط بهعنوان str نوعدهی شده باشد، سازگار نیست. رشتهای که با ترکیب اشیای دارای نوع LiteralString ایجاد شده باشد نیز بهعنوان LiteralString قابلقبول است.
مثال:
def run_query(sql: LiteralString) -> None:
...
def caller(arbitrary_string: str, literal_string: LiteralString) -> None:
run_query("SELECT * FROM students") # OK
run_query(literal_string) # OK
run_query("SELECT * FROM " + literal_string) # OK
run_query(arbitrary_string) # type checker error
run_query( # type checker error
f"SELECT * FROM students WHERE name = {arbitrary_string}"
)
LiteralString برای APIهای حساسی مفید است که در آنها رشتههای دلخواه تولیدشده توسط کاربر ممکن است مشکلساز شوند. برای مثال، دو مورد بالا که باعث ایجاد خطاهای بررسیکننده نوع میشوند، ممکن است در برابر حمله تزریق SQL آسیبپذیر باشند.
برای جزئیات بیشتر، PEP 675 را ببینید.
اضافه شده در نسخهی 3.11.
-
typing.Never¶
-
typing.NoReturn¶
Never و NoReturn نوع پایینی (bottom type) را نشان میدهند، نوعی که هیچ عضوی ندارد.
میتوان از آنها برای نشان دادن این موضوع استفاده کرد که یک تابع هرگز برنمیگردد، مانند sys.exit():
from typing import Never # or NoReturn
def stop() -> Never:
raise RuntimeError('no way')
یا برای تعریف تابعی که هرگز نباید فراخوانی شود، زیرا هیچ آرگومان معتبری وجود ندارد، مانند assert_never():
from typing import Never # or NoReturn
def never_call_me(arg: Never) -> None:
pass
def int_or_str(arg: int | str) -> None:
never_call_me(arg) # type checker error
match arg:
case int():
print("It's an int")
case str():
print("It's a str")
case _:
never_call_me(arg) # OK, arg is of type Never (or NoReturn)
Never و NoReturn در سیستم نوع معنای یکسانی دارند و بررسیکنندههای نوع ایستا هر دو را بهطور معادل در نظر میگیرند.
اضافه شده در نسخهی 3.6.2: NoReturn اضافه شد.
اضافه شده در نسخهی 3.11: Never اضافه شد.
-
typing.Self¶
نوع خاصی برای نمایش کلاس دربرگیرندهی فعلی.
برای مثال:
from typing import Self, reveal_type
class Foo:
def return_self(self) -> Self:
...
return self
class SubclassOfFoo(Foo): pass
reveal_type(Foo().return_self()) # Revealed type is "Foo"
reveal_type(SubclassOfFoo().return_self()) # Revealed type is "SubclassOfFoo"
این حاشیهنویسی از نظر معنایی معادل مورد زیر است، هرچند بهشکلی مختصرتر:
from typing import TypeVar
Self = TypeVar("Self", bound="Foo")
class Foo:
def return_self(self: Self) -> Self:
...
return self
بهطور کلی، اگر چیزی self را برمیگرداند، مانند مثالهای بالا، باید از Self بهعنوان حاشیهنویسی بازگشت استفاده کنید. اگر Foo.return_self بهگونهای حاشیهنویسی شده باشد که "Foo" را برمیگرداند، آنگاه بررسیکننده نوع، شیء برگرداندهشده از SubclassOfFoo.return_self را از نوع Foo استنباط میکند، نه SubclassOfFoo.
از دیگر موارد استفادهی رایج میتوان به:
اگر تضمینی وجود ندارد که وقتی از کلاس زیرکلاس ساخته میشود، متد نمونهای از یک زیرکلاس را برگرداند، نباید از Self بهعنوان حاشیهنویسی بازگشت (return annotation) استفاده کنید:
class Eggs:
# Self would be an incorrect return annotation here,
# as the object returned is always an instance of Eggs,
# even in subclasses
def returns_eggs(self) -> "Eggs":
return Eggs()
برای جزئیات بیشتر، PEP 673 را ببینید.
اضافه شده در نسخهی 3.11.
-
typing.TypeAlias¶
حاشیهنویسی ویژه برای اعلام صریح یک نام مستعار نوع.
برای مثال:
from typing import TypeAlias
Factors: TypeAlias = list[int]
TypeAlias بهویژه در نسخههای قدیمیتر پایتون برای حاشیهنویسی نامهای مستعاری که از ارجاعهای پیشرو (forward references) استفاده میکنند، مفید است، زیرا ممکن است برای بررسیکنندههای نوع تشخیص این موارد از انتسابهای معمولی متغیر دشوار باشد:
from typing import Generic, TypeAlias, TypeVar
T = TypeVar("T")
# "Box" does not exist yet,
# so we have to use quotes for the forward reference on Python <3.12.
# Using ``TypeAlias`` tells the type checker that this is a type alias declaration,
# not a variable assignment to a string.
BoxOfStrings: TypeAlias = "Box[str]"
class Box(Generic[T]):
@classmethod
def make_box_of_strings(cls) -> BoxOfStrings: ...
برای جزئیات بیشتر، PEP 613 را ببینید.
اضافه شده در نسخهی 3.10.
منسوخ شده از نسخهی 3.12: TypeAlias به نفع دستور type منسوخ شده است، که نمونههایی از TypeAliasType ایجاد میکند و بهصورت ذاتی از ارجاعهای پیشرو پشتیبانی میکند. توجه داشته باشید که با وجود اینکه TypeAlias و TypeAliasType اهداف مشابهی دارند و نامهای مشابهی دارند، این دو متمایز هستند و دومی نوع اولی نیست. در حال حاضر برنامهای برای حذف TypeAlias وجود ندارد، اما کاربران تشویق میشوند به دستورات type مهاجرت کنند.
شکلهای خاص¶
این موارد میتوانند بهعنوان نوع در حاشیهنویسیها استفاده شوند. همهی آنها از زیرنویسی با [] پشتیبانی میکنند، اما هر کدام نحوِ یکتایی دارند.
-
class typing.Union¶
نوع Union؛ Union[X, Y] معادل X | Y است و به معنای X یا Y است.
برای تعریف یک اجتماع (union)، برای نمونه از Union[int, str] یا شکل کوتاه int | str استفاده کنید. استفاده از آن شکل کوتاه توصیه میشود. جزئیات:
آرگومانها باید نوع باشند و باید حداقل یکی وجود داشته باشد.
اجتماعهای تودرتو مسطح میشوند، برای مثال:
Union[Union[int, str], float] == Union[int, str, float]
با این حال، این موضوع در مورد اجتماعهای ارجاعشده از طریق یک نام مستعار نوع صدق نمیکند، تا از اجبار به ارزیابی TypeAliasType زیرین جلوگیری شود:
type A = Union[int, str]
Union[A, float] != Union[int, str, float]
Unionهای با یک آرگومان حذف میشوند، مثلاً:
Union[int] == int # سازنده در واقع int را برمیگرداند
آرگومانهای زائد نادیده گرفته میشوند، برای مثال:
Union[int, str, int] == Union[int, str] == int | str
هنگام مقایسه اجتماعها (unions)، ترتیب آرگومانها نادیده گرفته میشود، برای مثال:
Union[int, str] == Union[str, int]
نمیتوانید از Union زیرکلاس بسازید یا آن را نمونهسازی کنید.
شما نمیتوانید Union[X][Y] را بنویسید.
تغییر یافته در نسخهی 3.7: زیرکلاسهای صریح را در رانتایم از اجتماعها (unions) حذف نکنید.
تغییر یافته در نسخهی 3.10: اکنون میتوان اجتماعها را بهصورت X | Y نوشت. عبارات نوع اجتماعای را ببینید.
تغییر یافته در نسخهی 3.14: types.UnionType اکنون یک نام مستعار برای Union است، و هر دو Union[int, str] و int | str نمونههایی از یک کلاس را ایجاد میکنند. برای بررسی اینکه آیا یک شیء در رانتایم یک Union است، از isinstance(obj, Union) استفاده کنید. برای سازگاری با نسخههای پیشین پایتون، از get_origin(obj) is typing.Union or get_origin(obj) is types.UnionType استفاده کنید.
-
typing.Optional¶
Optional[X] معادل X | None (یا Union[X, None]) است.
توجه داشته باشید که این مفهوم با آرگومان اختیاری یکسان نیست؛ آرگومان اختیاری آرگومانی است که مقدار پیشفرض دارد. یک آرگومان اختیاری دارای مقدار پیشفرض، فقط به این دلیل که اختیاری است، نیازی به مشخصکننده Optional در حاشیهنویسی نوع خود ندارد. برای مثال:
def foo(arg: int = 0) -> None:
...
از سوی دیگر، اگر مقدار صریح None مجاز باشد، استفاده از Optional مناسب است، چه آرگومان اختیاری باشد و چه نباشد. برای مثال:
def foo(arg: Optional[int] = None) -> None:
...
-
typing.Concatenate¶
شکل ویژه برای حاشیهنویسی توابع مرتبهبالاتر.
میتوان از Concatenate به همراه Callable و ParamSpec برای حاشیهنویسی یک فراخوانیپذیر مرتبه بالاتر استفاده کرد که پارامترهای یک فراخوانیپذیر دیگر را اضافه، حذف یا تبدیل میکند. نحوه استفاده به شکل Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable] است. Concatenate زمانی معتبر است که در راهنماهای نوع Callable و هنگام نمونهسازی کلاسهای عام تعریفشده توسط کاربر با پارامترهای ParamSpec استفاده شود. آخرین پارامتر Concatenate باید یک ParamSpec یا سهنقطه (...) باشد.
برای مثال، برای حاشیهنویسی یک دکوراتور with_lock که یک threading.Lock را در اختیار تابع دکوریتشده قرار میدهد، میتوان از Concatenate استفاده کرد تا نشان داده شود که with_lock یک شیء فراخوانیپذیر با امضای نوعی متفاوت برمیگرداند و انتظار یک شیء فراخوانیپذیر را دارد که Lock را بهعنوان اولین آرگومان میگیرد. در این حالت، ParamSpec نشان میدهد که انواع پارامترهای شیء فراخوانیپذیر برگرداندهشده به انواع پارامترهای شیء فراخوانیپذیر ورودی وابسته است:
from collections.abc import Callable
from threading import Lock
from typing import Concatenate
# Use this lock to ensure that only one thread is executing a function
# at any time.
my_lock = Lock()
def with_lock[**P, R](f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
'''دکوراتوری ایمن از نظر نوع که یک قفل فراهم میکند.'''
def inner(*args: P.args, **kwargs: P.kwargs) -> R:
# Provide the lock as the first argument.
return f(my_lock, *args, **kwargs)
return inner
@with_lock
def sum_threadsafe(lock: Lock, numbers: list[float]) -> float:
'''اعداد یک فهرست را بهصورت نخایمن با هم جمع میکند.'''
with lock:
return sum(numbers)
# We don't need to pass in the lock ourselves thanks to the decorator.
sum_threadsafe([1.1, 2.2, 3.3])
اضافه شده در نسخهی 3.10.
-
typing.Literal¶
شکل خاص نوعدهی برای تعریف «انواع لفظی» (literal types).
میتوان از Literal استفاده کرد تا به بررسیکنندههای نوع نشان داده شود که شیء حاشیهگذاریشده دارای مقداری معادل یکی از مقادیر لفظی ارائهشده است.
برای مثال:
def validate_simple(data: Any) -> Literal[True]: # always returns True
...
type Mode = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: Mode) -> str:
...
open_helper('/some/path', 'r') # Passes type check
open_helper('/other/path', 'typo') # Error in type checker
Literal[...] قابل زیرکلاسسازی نیست. در رانتایم، هر مقدار دلخواهی بهعنوان آرگومان نوع برای Literal[...] مجاز است، اما بررسیکنندههای نوع ممکن است محدودیتهایی اعمال کنند. برای جزئیات بیشتر دربارهی انواع لفظی (literal types)، PEP 586 را ببینید.
جزئیات بیشتر:
آرگومانها باید مقادیر لفظی باشند و باید دستکم یک آرگومان وجود داشته باشد.
انواع Literal تودرتو تخت میشوند، مثلاً:
assert Literal[Literal[1, 2], 3] == Literal[1, 2, 3]
با این حال، این موضوع در مورد انواع Literal که از طریق یک ناممستعار نوع به آنها ارجاع داده شدهاند اعمال نمیشود، تا از اجبار به ارزیابی TypeAliasType زیربنایی جلوگیری شود:
type A = Literal[1, 2]
assert Literal[A, 3] != Literal[1, 2, 3]
آرگومانهای زائد نادیده گرفته میشوند، برای مثال:
assert Literal[1, 2, 1] == Literal[1, 2]
هنگام مقایسهی مقادیر لفظی، ترتیب آرگومانها نادیده گرفته میشود، برای مثال:
assert Literal[1, 2] == Literal[2, 1]
شما نمیتوانید از Literal زیرکلاس بسازید یا آن را نمونهسازی کنید.
شما نمیتوانید Literal[X][Y] را بنویسید.
تغییر یافته در نسخهی 3.9.1: اکنون Literal پارامترهای تکراری را حذف میکند. مقایسههای برابری اشیای Literal دیگر به ترتیب وابسته نیستند. اشیای Literal اکنون در حین مقایسههای برابری، اگر یکی از پارامترهای آنها hashable نباشد، استثنای TypeError را پرتاب میکنند.
-
typing.ClassVar¶
ساختار نوع ویژه برای علامتگذاری متغیرهای کلاس.
همانطور که در PEP 526 معرفی شد، یک حاشیهنویسی متغیر که در ClassVar قرار گرفته باشد، نشان میدهد که یک ویژگی مشخص برای استفاده بهعنوان متغیر کلاس در نظر گرفته شده است و نباید روی نمونههای آن کلاس تنظیم شود. استفاده:
class Starship:
stats: ClassVar[dict[str, int]] = {} # class variable
damage: int = 10 # instance variable
ClassVar فقط نوعها را میپذیرد و نمیتوان آن را بیشتر با کروشه پارامتردار (subscribed) کرد.
ClassVar خودش یک کلاس نیست و نمیتوان از آن با isinstance() یا issubclass() استفاده کرد. ClassVar رفتار رانتایم پایتون را تغییر نمیدهد، اما بررسیکنندههای نوع ایستا میتوانند از آن استفاده کنند. برای مثال، ممکن است یک بررسیکننده نوع کد زیر را بهعنوان خطا علامتگذاری کند:
enterprise_d = Starship(3000)
enterprise_d.stats = {} # Error, setting class variable on instance
Starship.stats = {} # This is OK
اضافه شده در نسخهی 3.5.3.
تغییر یافته در نسخهی 3.13: اکنون میتوان ClassVar را در Final تودرتو کرد و برعکس.
-
typing.Final¶
ساختار ویژهی نوعدهی برای نشان دادن نامهای نهایی به بررسیکنندههای نوع.
نامهای نهایی را نمیتوان در هیچ محدودهای دوباره انتساب داد. نامهای نهایی اعلامشده در محدودههای کلاس را نمیتوان در زیرکلاسها بازنویسی کرد.
برای مثال:
MAX_SIZE: Final = 9000
MAX_SIZE += 1 # Error reported by type checker
class Connection:
TIMEOUT: Final[int] = 10
class FastConnector(Connection):
TIMEOUT = 1 # Error reported by type checker
هیچ بررسیای در رانتایم برای این ویژگیها انجام نمیشود. برای جزئیات بیشتر PEP 591 را ببینید.
تغییر یافته در نسخهی 3.13: اکنون میتوان Final را در ClassVar و برعکس، بهصورت تودرتو استفاده کرد.
-
typing.Required¶
ساختار خاص تایپ برای علامتگذاری یک کلید در TypedDict بهعنوان ضروری.
این عمدتاً برای TypedDictهایی با total=False مفید است. برای جزئیات بیشتر، TypedDict و PEP 655 را ببینید.
اضافه شده در نسخهی 3.11.
-
typing.NotRequired¶
ساختار خاص تایپینگ برای علامتگذاری یک کلید TypedDict بهعنوان کلیدی که ممکن است موجود نباشد.
برای جزئیات بیشتر TypedDict و PEP 655 را ببینید.
اضافه شده در نسخهی 3.11.
-
typing.ReadOnly¶
یک ساختار خاص تایپینگ برای علامتگذاری یک آیتم از یک TypedDict بهعنوان فقطخواندنی.
برای مثال:
class Movie(TypedDict):
title: ReadOnly[str]
year: int
def mutate_movie(m: Movie) -> None:
m["year"] = 1999 # allowed
m["title"] = "The Matrix" # type checker error
هیچ بررسیای در رانتایم برای این ویژگی وجود ندارد.
برای جزئیات بیشتر، TypedDict و PEP 705 را ببینید.
اضافه شده در نسخهی 3.13.
-
typing.Annotated¶
شکل ویژهی نوعدهی برای افزودن فرادادهی مختص به زمینه به یک حاشیهنویسی .
با استفاده از حاشیهنویسی Annotated[T, x]، فراداده x را به نوع T اضافه کنید. فرادادهی افزودهشده با Annotated میتواند توسط ابزارهای تحلیل ایستا یا در رانتایم مورد استفاده قرار گیرد. در رانتایم، فراداده در ویژگی __metadata__ ذخیره میشود.
اگر یک کتابخانه یا ابزار با یک حاشیهنویسی Annotated[T, x] مواجه شود و منطق خاصی برای فراداده نداشته باشد، باید فراداده را نادیده بگیرد و حاشیهنویسی را بهسادگی بهعنوان T در نظر بگیرد. از این رو، Annotated میتواند برای کدی که میخواهد از حاشیهنویسیها برای اهدافی خارج از سیستم نوعدهی ایستای پایتون استفاده کند، مفید باشد.
استفاده از Annotated[T, x] بهعنوان یک حاشیهنویسی، همچنان امکان بررسی ایستای نوع برای T را فراهم میکند، زیرا بررسیکنندههای نوع بهسادگی فرادادهی x را نادیده میگیرند. به این ترتیب، Annotated با دکوراتور @no_type_check تفاوت دارد، که میتواند برای افزودن حاشیهنویسیهایی خارج از محدودهی سیستم تایپ نیز استفاده شود، اما بررسی نوع را برای یک تابع یا کلاس بهطور کامل غیرفعال میکند.
مسئولیت نحوه تفسیر فراداده بر عهده ابزار یا کتابخانهای است که با یک حاشیهنویسی Annotated مواجه میشود. ابزار یا کتابخانهای که با یک نوع Annotated مواجه میشود، میتواند عناصر فراداده را پیمایش کند تا تشخیص دهد که آیا آنها مورد توجه هستند یا خیر (برای مثال، با استفاده از isinstance()).
-
Annotated[<type>, <metadata>]
در اینجا مثالی از نحوهی استفاده از Annotated برای افزودن فراداده به حاشیهنویسیهای نوع، در صورتی که بخواهید تحلیل بازه انجام دهید، آمده است:
@dataclass
class ValueRange:
lo: int
hi: int
T1 = Annotated[int, ValueRange(-10, 5)]
T2 = Annotated[T1, ValueRange(-20, 3)]
اولین آرگومان Annotated باید نوع معتبری باشد. از آنجا که Annotated از آرگومانهای با تعداد متغیر پشتیبانی میکند، میتوان چندین المان فراداده را فراهم کرد. ترتیب المانهای فراداده حفظ میشود و در بررسیهای برابری اهمیت دارد:
@dataclass
class ctype:
kind: str
a1 = Annotated[int, ValueRange(3, 10), ctype("char")]
a2 = Annotated[int, ctype("char"), ValueRange(3, 10)]
assert a1 != a2 # Order matters
تصمیمگیری دربارهی اینکه آیا کلاینت مجاز است چندین عنصر فراداده را به یک حاشیهنویسی اضافه کند و نحوهی ادغام آن حاشیهنویسیها، بر عهدهی ابزاری است که حاشیهنویسیها را مصرف میکند.
انواع Annotated تودرتو تخت میشوند. ترتیب عناصر فراداده از درونیترین حاشیهنویسی آغاز میشود:
assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
int, ValueRange(3, 10), ctype("char")
]
با این حال، این مورد شامل انواع Annotated نمیشود که از طریق یک نام مستعار نوع به آنها ارجاع داده شده است، تا از اجبار به ارزیابی TypeAliasType زیربنایی جلوگیری شود:
type From3To10[T] = Annotated[T, ValueRange(3, 10)]
assert Annotated[From3To10[int], ctype("char")] != Annotated[
int, ValueRange(3, 10), ctype("char")
]
عناصر فرادادهی تکراری حذف نمیشوند:
assert Annotated[int, ValueRange(3, 10)] != Annotated[
int, ValueRange(3, 10), ValueRange(3, 10)
]
میتوان از Annotated همراه با نامهای مستعار تودرتو و عام استفاده کرد:
@dataclass
class MaxLen:
value: int
type Vec[T] = Annotated[list[tuple[T, T]], MaxLen(10)]
# When used in a type annotation, a type checker will treat "V" the same as
# ``Annotated[list[tuple[int, int]], MaxLen(10)]``:
type V = Vec[int]
Annotated را نمیتوان با یک TypeVarTuple واگشاییشده استفاده کرد:
type Variadic[*Ts] = Annotated[*Ts, Ann1] = Annotated[T1, T2, T3, ..., Ann1] # NOT valid
که در آن T1، T2، ... TypeVars هستند. این نامعتبر است، زیرا تنها یک نوع باید به Annotated داده شود.
بهطور پیشفرض، get_type_hints() فراداده را از حاشیهنویسیها حذف میکند. include_extras=True را ارسال کنید تا فراداده حفظ شود:
>>> from typing import Annotated, get_type_hints
>>> def func(x: Annotated[int, "metadata"]) -> None: pass
...
>>> get_type_hints(func)
{'x': <class 'int'>, 'return': <class 'NoneType'>}
>>> get_type_hints(func, include_extras=True)
{'x': typing.Annotated[int, 'metadata'], 'return': <class 'NoneType'>}
در رانتایم، میتوان فرادادهی مرتبط با یک نوع Annotated را از طریق ویژگی __metadata__ بازیابی کرد:
>>> from typing import Annotated
>>> X = Annotated[int, "very", "important", "metadata"]
>>> X
typing.Annotated[int, 'very', 'important', 'metadata']
>>> X.__metadata__
('very', 'important', 'metadata')
اگر میخواهید نوع اصلی پوشیدهشده با Annotated را بازیابی کنید، از ویژگی __origin__ استفاده کنید:
>>> from typing import Annotated, get_origin
>>> Password = Annotated[str, "secret"]
>>> Password.__origin__
<class 'str'>
توجه داشته باشید که استفاده از get_origin() خود Annotated را برمیگرداند:
>>> get_origin(Password)
typing.Annotated
همچنین ببینید
- PEP 593 - حاشیهنویسیهای انعطافپذیر برای توابع و متغیرها
PEP معرفیکننده Annotated به کتابخانه استاندارد.
-
typing.TypeForm¶
یک فرم خاص که نمایانگر مقداری است که از ارزیابی یک عبارت نوع به دست میآید.
این مقدار اطلاعات ارائهشده در عبارت نوع را کدگذاری میکند و نمایانگر نوع توصیفشده توسط آن عبارت نوع است.
هنگنگامی که در یک عبارت نوع استفاده میشود، TypeForm مجموعهای از شیءهای فرم نوع را توصیف میکند. این فرم یک آرگومان نوع منفرد را میپذیرد که باید یک عبارت نوع معتبر باشد. TypeForm[T] مجموعهای از تمام شیءهای فرم نوع را توصیف میکند که نمایانگر نوع T یا انواع قابل انتساب به T هستند.
TypeForm(obj) به سادگی obj را بدون تغییر برمیگرداند. این کار برای نشانهگذاری صریح یک مقدار به عنوان فرم نوع برای بررسیکنندههای ایستای نوع مفید است.
مثال:
from typing import Any, TypeForm
def cast[T](typ: TypeForm[T], value: Any) -> T: ...
reveal_type(cast(int, "x")) # Revealed type is "int"
برای جزئیات بیشتر به PEP 747 مراجعه کنید.
اضافه شده در نسخهی 3.15.
-
typing.TypeIs¶
ساختار خاص نوعدهی برای علامتگذاری توابع محمول نوع تعریفشده توسط کاربر.
میتوان از TypeIs برای حاشیهنویسی نوع بازگشتی یک تابع محمول نوع تعریفشده توسط کاربر استفاده کرد. TypeIs تنها یک آرگومان نوع میپذیرد. در رانتایم، توابعی که به این شکل حاشیهنویسی شدهاند باید یک مقدار بولی برگردانند و حداقل یک آرگومان جایگاهی دریافت کنند.
TypeIs در پی بهرهگیری از باریکسازی نوع (type narrowing) است -- روشی که بررسیکنندههای نوع ایستا برای تعیین نوع دقیقتر یک عبارت در جریان کد برنامه از آن استفاده میکنند. معمولاً باریکسازی نوع با تحلیل جریان کد شرطی و اعمال باریکسازی بر یک بلوک کد انجام میشود. در اینجا، عبارت شرطی گاهی «محمول نوع » نامیده میشود:
def is_str(val: str | float):
# "isinstance" type predicate
if isinstance(val, str):
# Type of ``val`` is narrowed to ``str``
...
else:
# Else, type of ``val`` is narrowed to ``float``.
...
گاهی اوقات استفاده از یک تابع بولی تعریفشده توسط کاربر بهعنوان محمول نوع میتواند مناسب باشد. چنین تابعی باید از TypeIs[...] یا TypeGuard بهعنوان نوع بازگشتی خود استفاده کند تا بررسیکنندههای نوع ایستا از این قصد آگاه شوند. TypeIs معمولاً رفتاری شهودیتر از TypeGuard دارد، اما زمانی که انواع ورودی و خروجی ناسازگار باشند (برای مثال، list[object] به list[int]) یا زمانی که تابع برای همه نمونههای نوع محدودشده True را برنمیگرداند، نمیتوان از آن استفاده کرد.
استفاده از -> TypeIs[NarrowedType] به بررسیکننده نوع ایستا میگوید که برای یک تابع مشخص:
مقدار بازگشتی یک بولی است.
اگر مقدار بازگشتی True باشد، نوع آرگومان آن برابر با اشتراک نوع اصلی آرگومان و NarrowedType است.
اگر مقدار بازگشتی False باشد، نوع آرگومان آن محدود میشود تا NarrowedType را شامل نشود.
برای مثال:
from typing import assert_type, final, TypeIs
class Parent: pass
class Child(Parent): pass
@final
class Unrelated: pass
def is_parent(val: object) -> TypeIs[Parent]:
return isinstance(val, Parent)
def run(arg: Child | Unrelated):
if is_parent(arg):
# Type of ``arg`` is narrowed to the intersection
# of ``Parent`` and ``Child``, which is equivalent to
# ``Child``.
assert_type(arg, Child)
else:
# Type of ``arg`` is narrowed to exclude ``Parent``,
# so only ``Unrelated`` is left.
assert_type(arg, Unrelated)
نوع درون TypeIs باید با نوع آرگومان تابع سازگار باشد؛ در غیر این صورت، بررسیکنندههای نوع ایستا خطایی پرتاب میکنند. یک تابع TypeIs که بهصورت نادرست نوشته شده باشد میتواند به رفتار ناسالم در سیستم نوع منجر شود؛ مسئولیت کاربر است که چنین توابعی را به شیوهای ایمن از نظر نوع بنویسد.
اگر تابع TypeIs یک متد کلاس یا متد نمونه باشد، نوع موجود در TypeIs به نوع دومین پارامتر (پس از cls یا self) نگاشت میشود.
بهطور خلاصه، قالب def foo(arg: TypeA) -> TypeIs[TypeB]: ... به این معناست که اگر foo(arg) مقدار True را برگرداند، arg یک نمونه از TypeB است، و اگر مقدار False را برگرداند، نمونهای از TypeB نیست.
TypeIs با متغیرهای نوع نیز کار میکند. برای اطلاعات بیشتر، PEP 742 (باریکسازی انواع با TypeIs) را ببینید.
اضافه شده در نسخهی 3.13.
-
typing.TypeGuard¶
ساختار خاص نوعدهی برای علامتگذاری توابع محمول نوع تعریفشده توسط کاربر.
توابع محمول نوع، توابع تعریفشده توسط کاربر هستند که این را بازمیگردانند که آیا آرگومان خود نمونهای از یک نوع خاص است یا خیر. TypeGuard مشابه TypeIs کار میکند، اما تأثیرات ظریف و متفاوتی بر رفتار بررسی نوع دارد (در زیر ببینید).
استفاده از -> TypeGuard به بررسیگر نوع ایستا میگوید که برای یک تابع معین:
مقدار بازگشتی یک بولی است.
اگر مقدار بازگشتی True باشد، نوع آرگومان آن، نوع درون TypeGuard است.
TypeGuard همچنین با متغیرهای نوع کار میکند. برای جزئیات بیشتر، PEP 647 را ببینید.
برای مثال:
def is_str_list(val: list[object]) -> TypeGuard[list[str]]:
'''Determines whether all objects in the list are strings'''
return all(isinstance(x, str) for x in val)
def func1(val: list[object]):
if is_str_list(val):
# Type of ``val`` is narrowed to ``list[str]``.
print(" ".join(val))
else:
# Type of ``val`` remains as ``list[object]``.
print("Not a list of strings!")
TypeIs و TypeGuard به روشهای زیر تفاوت دارند:
TypeIs نیاز دارد که نوع محدودشده یک زیرنوع از نوع ورودی باشد، در حالی که TypeGuard چنین الزامی ندارد. دلیل اصلی این است که امکان مواردی مانند محدود کردن list[object] به list[str] فراهم شود، هرچند دومی زیرنوعی از اولی نیست، زیرا list ناوردا است.
هنگامی که یک تابع TypeGuard مقدار True را برمیگرداند، بررسیکنندههای نوع، نوع متغیر را دقیقاً به نوع TypeGuard محدود میکنند. هنگامی که یک تابع TypeIs مقدار True را برمیگرداند، بررسیکنندههای نوع میتوانند با ترکیب نوع از پیش شناختهشدهی متغیر با نوع TypeIs، نوع دقیقتری را استنتاج کنند. (از نظر فنی، به این نوع، نوع تقاطعی گفته میشود.)
هنگامی که یک تابع TypeGuard False را برمیگرداند، بررسیکنندههای نوع بههیچوجه نمیتوانند نوع متغیر را محدودتر کنند. هنگامی که یک تابع TypeIs False را برمیگرداند، بررسیکنندههای نوع میتوانند نوع متغیر را محدودتر کنند تا نوع TypeIs را حذف کنند.
اضافه شده در نسخهی 3.10.
-
typing.Unpack¶
عملگر تایپینگ برای نمادگذاری مفهومی یک شیء بهعنوان واگشاییشده.
برای مثال، استفاده از عملگر واگشایی * بر روی یک تاپل متغیر نوع معادل استفاده از Unpack برای علامتگذاری آن تاپل متغیر نوع بهعنوان واگشاییشده است:
Ts = TypeVarTuple('Ts')
tup: tuple[*Ts]
# Effectively does:
tup: tuple[Unpack[Ts]]
در واقع، میتوان از Unpack و * بهجای یکدیگر در زمینهی انواع typing.TypeVarTuple و builtins.tuple استفاده کرد. ممکن است Unpack را بهصورت صریح در نسخههای قدیمیتر پایتون ببینید، یعنی در مواردی که امکان استفاده از * در برخی جایگاهها وجود نداشت:
# In older versions of Python, TypeVarTuple and Unpack
# are located in the `typing_extensions` backports package.
from typing_extensions import TypeVarTuple, Unpack
Ts = TypeVarTuple('Ts')
tup: tuple[*Ts] # Syntax error on Python <= 3.10!
tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible
همچنین میتوان از Unpack به همراه typing.TypedDict برای نوعدهی **kwargs در امضای تابع استفاده کرد:
from typing import TypedDict, Unpack
class Movie(TypedDict):
name: str
year: int
# This function expects two keyword arguments - `name` of type `str`
# and `year` of type `int`.
def foo(**kwargs: Unpack[Movie]): ...
برای جزئیات بیشتر درباره استفاده از Unpack برای نوعدهی **kwargs، PEP 692 را ببینید.
اضافه شده در نسخهی 3.11.
ساخت انواع عام و نامهای مستعار نوع¶
نباید از کلاسهای زیر بهصورت مستقیم بهعنوان حاشیهنویسی استفاده شود. هدف مورد نظر آنها این است که اجزای سازندهای برای ایجاد انواع عام و نامهای مستعار نوع باشند.
این اشیاء را میتوان از طریق سینتکس ویژه (فهرستهای پارامتر نوع و دستور type) ایجاد کرد. برای سازگاری با پایتون 3.11 و نسخههای پیش از آن، میتوان آنها را بدون سینتکس اختصاصی نیز ایجاد کرد، همانطور که در زیر مستند شده است.
-
class typing.Generic¶
کلاس پایه انتزاعی برای انواع عام.
یک نوع عام معمولاً با افزودن فهرستی از پارامترهای نوع پس از نام کلاس تعریف میشود:
class Mapping[KT, VT]:
def __getitem__(self, key: KT) -> VT:
...
# Etc.
چنین کلاسی بهطور ضمنی از Generic ارثبری میکند. معنای رانتایمی این سینتکس در مرجع زبان بحث شده است.
سپس میتوان از این کلاس بهصورت زیر استفاده کرد:
def lookup_name[X, Y](mapping: Mapping[X, Y], key: X, default: Y) -> Y:
try:
return mapping[key]
except KeyError:
return default
در اینجا کروشههای پس از نام تابع نشاندهندهی یک تابع عام هستند.
برای سازگاری با عقبگرد، کلاسهای عام همچنین میتوانند با بهارثبری صریح از Generic اعلام شوند. در این حالت، پارامترهای نوع باید بهصورت جداگانه اعلام شوند:
KT = TypeVar('KT')
VT = TypeVar('VT')
class Mapping(Generic[KT, VT]):
def __getitem__(self, key: KT) -> VT:
...
# Etc.
-
class typing.TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False, default=typing.NoDefault)¶
متغیر نوع.
روش ترجیحی برای ایجاد یک متغیر نوع، استفاده از سینتکس اختصاصی برای توابع عام، کلاسهای عام و نامهای مستعار نوع عام است:
class Sequence[T]: # T is a TypeVar
...
همچنین میتوان از این سینتکس برای ایجاد متغیرهای نوع کراندار و مقید استفاده کرد:
class StrSequence[S: str]: # S is a TypeVar with a `str` upper bound;
... # we can say that S is "bounded by `str`"
class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes
...
با این حال، در صورت تمایل، متغیرهای نوع بازاستفادهپذیر را نیز میتوان بهصورت دستی ساخت، به این صورت:
T = TypeVar('T') # Can be anything
S = TypeVar('S', bound=str) # Can be any subtype of str
A = TypeVar('A', str, bytes) # Must be exactly str or bytes
متغیرهای نوع عمدتاً برای کمک به بررسیکنندههای نوع ایستا وجود دارند. این متغیرها بهعنوان پارامترهایی برای انواع عام و همچنین برای تعاریف تابع عام و نام مستعار نوع به کار میروند. برای اطلاعات بیشتر درباره انواع عام، Generic را ببینید. توابع عام بهصورت زیر کار میکنند:
def repeat[T](x: T, n: int) -> Sequence[T]:
"""Return a list containing n references to x."""
return [x]*n
def print_capitalized[S: str](x: S) -> S:
"""Print x capitalized, and return x."""
print(x.capitalize())
return x
def concatenate[A: (str, bytes)](x: A, y: A) -> A:
"""Add two strings or bytes objects together."""
return x + y
توجه داشته باشید که متغیرهای نوع میتوانند کراندار، مقید یا هیچکدام باشند، اما نمیتوانند همزمان هم کراندار و هم مقید باشند.
واریانس (variance) متغیرهای نوع، هنگامی که آنها از طریق سینتکس پارامتر نوع ایجاد میشوند یا هنگامی که infer_variance=True ارسال میشود، توسط بررسیکنندههای نوع استنتاج میشود. متغیرهای نوعی که بهصورت دستی ایجاد شدهاند، میتوانند با ارسال covariant=True یا contravariant=True بهصراحت بهعنوان هموردا یا پادوردا (contravariant) علامتگذاری شوند. بهطور پیشفرض، متغیرهای نوعی که بهصورت دستی ایجاد شدهاند، ناوردا (invariant) هستند. برای جزئیات بیشتر، PEP 484 و PEP 695 را ببینید.
متغیرهای نوع کراندار و متغیرهای نوع مقید از چند جهت مهم معنای متفاوتی دارند. استفاده از یک متغیر نوع کراندار به این معناست که TypeVar با استفاده از خاصترین نوع ممکن حل میشود:
x = print_capitalized('a string')
reveal_type(x) # revealed type is str
class StringSubclass(str):
pass
y = print_capitalized(StringSubclass('another string'))
reveal_type(y) # revealed type is StringSubclass
z = print_capitalized(45) # error: int is not a subtype of str
کران بالای یک متغیر نوع میتواند یک نوع عینی، نوع انتزاعی (ABC یا Protocol)، یا حتی اجتماعی از انواع باشد:
# Can be anything with an __abs__ method
def print_abs[T: SupportsAbs](arg: T) -> None:
print("Absolute value:", abs(arg))
U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes
V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method
با این حال، استفاده از یک متغیر نوع محدودشده به این معناست که TypeVar فقط میتواند بهعنوان دقیقاً یکی از محدودیتهای دادهشده حل شود:
a = concatenate('one', 'two')
reveal_type(a) # revealed type is str
b = concatenate(StringSubclass('one'), StringSubclass('two'))
reveal_type(b) # revealed type is str, despite StringSubclass being passed in
c = concatenate('one', b'two') # error: type variable 'A' can be either str or bytes in a function call, but not both
در رانتایم، isinstance(x, T) استثنای TypeError را پرتاب میکند.
-
__name__¶
نام متغیر نوع.
-
__covariant__¶
اینکه آیا متغیر نوع بهصراحت بهعنوان هموردا علامتگذاری شده است یا خیر.
-
__contravariant__¶
اینکه آیا متغیر نوع بهطور صریح بهعنوان پادوردا (contravariant) علامتگذاری شده است یا خیر.
-
__infer_variance__¶
اینکه آیا واریانس متغیر نوع باید توسط بررسیکنندههای نوع استنباط شود.
اضافه شده در نسخهی 3.12.
-
__bound__¶
کران بالای متغیر نوع، در صورت وجود.
تغییر یافته در نسخهی 3.12: برای متغیرهای نوعی که از طریق سینتکس پارامتر نوع ایجاد میشوند، کران تنها هنگامی ارزیابی میشود که به ویژگی دسترسی پیدا شود، نه هنگامی که متغیر نوع ایجاد میشود (به ارزیابی تنبل مراجعه کنید).
-
evaluate_bound()¶
یک evaluate function متناظر با ویژگی __bound__. هنگامی که این متد مستقیماً فراخوانی شود، فقط از قالب VALUE پشتیبانی میکند، که معادل دسترسی مستقیم به ویژگی __bound__ است، اما میتوان شیء متد را به annotationlib.call_evaluate_function() ارسال کرد تا مقدار را در قالب متفاوتی ارزیابی کند.
اضافه شده در نسخهی 3.14.
-
__constraints__¶
یک تاپل شامل محدودیتهای متغیر نوع، در صورت وجود.
تغییر یافته در نسخهی 3.12: برای متغیرهای نوعی که از طریق سینتکس پارامتر نوع ایجاد میشوند، محدودیتها فقط در زمان دسترسی به ویژگی ارزیابی میشوند، نه در زمان ایجاد متغیر نوع (به ارزیابی تنبل مراجعه کنید).
-
evaluate_constraints()¶
یک evaluate function متناظر با ویژگی __constraints__. هنگامی که این متد مستقیماً فراخوانی شود، تنها از قالب VALUE پشتیبانی میکند، که معادل دسترسی مستقیم به ویژگی __constraints__ است، اما میتوان شیء متد را به annotationlib.call_evaluate_function() پاس داد تا مقدار در قالبی متفاوت ارزیابی شود.
اضافه شده در نسخهی 3.14.
-
__default__¶
مقدار پیشفرض متغیر نوع، یا typing.NoDefault اگر پیشفرضی نداشته باشد.
اضافه شده در نسخهی 3.13.
-
evaluate_default()¶
یک تابع ارزیابی متناظر با ویژگی __default__. هنگامی که این متد بهصورت مستقیم فراخوانی شود، تنها از قالب VALUE پشتیبانی میکند، که معادل دسترسی مستقیم به ویژگی __default__ است، اما میتوان شیء متد را به annotationlib.call_evaluate_function() ارسال کرد تا مقدار را در قالب دیگری ارزیابی کند.
اضافه شده در نسخهی 3.14.
-
has_default()¶
برمیگرداند که آیا متغیر نوع مقدار پیشفرض دارد یا خیر. این معادل بررسی این است که آیا __default__ تکنمونه typing.NoDefault نیست یا خیر، با این تفاوت که ارزیابی مقدار پیشفرضی که بهصورت تنبل ارزیابی میشود را تحمیل نمیکند.
اضافه شده در نسخهی 3.13.
تغییر یافته در نسخهی 3.12: اکنون میتوان متغیرهای نوع را با استفاده از سینتکس پارامتر نوع که در PEP 695 معرفی شده است، اعلام کرد. پارامتر infer_variance افزوده شد.
تغییر یافته در نسخهی 3.13: پشتیبانی از مقادیر پیشفرض اضافه شد.
-
class typing.TypeVarTuple(name, *, bound=None, covariant=False, contravariant=False, infer_variance=False, default=typing.NoDefault)¶
تاپل متغیر نوع. شکل تخصصی از متغیر نوع که امکان عامهای چندآرگومانی (variadic) را فراهم میکند.
تاپلهای متغیر نوع را میتوان در فهرستهای پارامتر نوع با یک ستاره (*) پیش از نام اعلام کرد:
def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0])
یا با فراخوانی صریح سازندهی TypeVarTuple:
T = TypeVar("T")
Ts = TypeVarTuple("Ts")
def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0])
یک متغیر نوع عادی، امکان پارامتریسازی با یک نوع واحد را فراهم میکند. در مقابل، یک تاپل متغیر نوع مانند تعداد دلخواهی از متغیرهای نوع که در یک تاپل قرار گرفتهاند عمل میکند و امکان پارامتریسازی با تعداد دلخواهی از انواع را فراهم میکند. برای مثال:
# T is bound to int, Ts is bound to ()
# Return value is (1,), which has type tuple[int]
move_first_element_to_last(tup=(1,))
# T is bound to int, Ts is bound to (str,)
# Return value is ('spam', 1), which has type tuple[str, int]
move_first_element_to_last(tup=(1, 'spam'))
# T is bound to int, Ts is bound to (str, float)
# Return value is ('spam', 3.0, 1), which has type tuple[str, float, int]
move_first_element_to_last(tup=(1, 'spam', 3.0))
# This fails to type check (and fails at runtime)
# because tuple[()] is not compatible with tuple[T, *Ts]
# (at least one element is required)
move_first_element_to_last(tup=())
به کاربرد عملگر واگشایی * در tuple[T, *Ts] توجه کنید. از نظر مفهومی، میتوانید Ts را تاپلی از متغیرهای نوع (T1, T2, ...) تصور کنید. در این صورت tuple[T, *Ts] به tuple[T, *(T1, T2, ...)] تبدیل میشود، که معادل tuple[T, T1, T2, ...] است. (توجه داشته باشید که در نسخههای قدیمیتر پایتون، ممکن است این بهجای آن با استفاده از Unpack نوشته شده باشد، بهصورت Unpack[Ts].)
تاپلهای متغیر نوع (type variable tuples) باید همیشه واگشایی شوند. این امر به تمایز تاپلهای متغیر نوع از متغیرهای نوع معمولی کمک میکند:
x: Ts # Not valid
x: tuple[Ts] # Not valid
x: tuple[*Ts] # The correct way to do it
تاپلهای متغیر نوع (type variable tuples) میتوانند در همان زمینههایی استفاده شوند که متغیرهای نوع معمولی استفاده میشوند. برای مثال، در تعریف کلاسها، آرگومانها و انواع بازگشتی:
class Array[*Shape]:
def __getitem__(self, key: tuple[*Shape]) -> float: ...
def __abs__(self) -> "Array[*Shape]": ...
def get_shape(self) -> tuple[*Shape]: ...
تاپلهای متغیر نوع میتوانند بهخوبی با متغیرهای نوع معمولی ترکیب شوند:
class Array[DType, *Shape]: # This is fine
pass
class Array2[*Shape, DType]: # This would also be fine
pass
class Height: ...
class Width: ...
float_array_1d: Array[float, Height] = Array() # Totally fine
int_array_2d: Array[int, Height, Width] = Array() # Yup, fine too
با این حال، توجه داشته باشید که حداکثر یک تاپل متغیر نوع (type variable tuple) میتواند در یک فهرست واحد از آرگومانهای نوع یا پارامترهای نوع ظاهر شود:
x: tuple[*Ts, *Ts] # Not valid
class Array[*Shape, *Shape]: # Not valid
pass
در نهایت، میتوان از یک متغیر نوع تاپلی واگشاییشده بهعنوان حاشیهنویسی نوع *args استفاده کرد:
def call_soon[*Ts](
callback: Callable[[*Ts], None],
*args: *Ts
) -> None:
...
callback(*args)
برخلاف حاشیهنویسیهای واگشایینشده برای *args — مثلاً *args: int، که مشخص میکند همه آرگومانها int هستند — *args: *Ts امکان ارجاع به انواع آرگومانهای تکی در *args را فراهم میکند. در اینجا، این امر به ما امکان میدهد اطمینان حاصل کنیم که انواع *args ارسالشده به call_soon با انواع آرگومانهای (جایگاهی) callback مطابقت دارند.
برای جزئیات بیشتر درباره تاپلهای متغیر نوع، PEP 646 را ببینید.
-
__name__¶
نام تاپل متغیر نوع.
-
__covariant__¶
اینکه آیا تاپل متغیر نوع صراحتاً به عنوان هموردا علامتگذاری شده است یا خیر.
اضافه شده در نسخهی 3.15.
-
__contravariant__¶
اینکه آیا تاپل متغیر نوع صراحتاً به عنوان پادوردا علامتگذاری شده است یا خیر.
اضافه شده در نسخهی 3.15.
-
__infer_variance__¶
اینکه آیا واریانس تاپل متغیر نوع باید توسط بررسیکنندههای نوع استنتاج شود یا خیر.
اضافه شده در نسخهی 3.15.
-
__default__¶
مقدار پیشفرض تاپل متغیر نوع، یا typing.NoDefault اگر پیشفرضی نداشته باشد.
اضافه شده در نسخهی 3.13.
-
evaluate_default()¶
یک evaluate function متناظر با ویژگی __default__. هنگامی که این متد بهصورت مستقیم فراخوانی شود، تنها از قالب VALUE پشتیبانی میکند، که معادل دسترسی مستقیم به ویژگی __default__ است، اما میتوان شیء متد را به annotationlib.call_evaluate_function() ارسال کرد تا مقدار در قالبی متفاوت ارزیابی شود.
اضافه شده در نسخهی 3.14.
-
has_default()¶
بازگشت میدهد که آیا تاپل متغیر نوع دارای مقدار پیشفرض است یا خیر. این معادل بررسی این است که آیا __default__ تکنمونهی typing.NoDefault نیست یا خیر، با این تفاوت که ارزیابی مقدار پیشفرض بهصورت تنبل ارزیابیشده را اجباری نمیکند.
اضافه شده در نسخهی 3.13.
تاپلهای متغیر نوع ایجادشده با covariant=True یا contravariant=True را میتوان برای اعلام انواع عام هموردا یا پادوردا استفاده کرد. آرگومان bound نیز مشابه TypeVar پذیرفته میشود، اما معناشناسی واقعی آن هنوز مشخص نشده است.
اضافه شده در نسخهی 3.11.
تغییر یافته در نسخهی 3.12: اکنون میتوان تاپلهای متغیر نوع را با استفاده از سینتکس پارامتر نوع که در PEP 695 معرفیشده است، اعلام کرد.
تغییر یافته در نسخهی 3.13: پشتیبانی از مقادیر پیشفرض اضافه شد.
تغییر یافته در نسخهی 3.15: پشتیبانی از پارامترهای bound، covariant، contravariant و infer_variance اضافه شد.
-
class typing.ParamSpec(name, *, bound=None, covariant=False, contravariant=False, infer_variance=False, default=typing.NoDefault)¶
متغیر مشخصات پارامتر. نسخهای تخصصی از متغیرهای نوع.
در فهرستهای پارامترهای نوع، میتوان مشخصههای پارامتر را با دو ستاره (**) تعریف کرد:
type IntFunc[**P] = Callable[P, int]
برای سازگاری با پایتون 3.11 و نسخههای قدیمیتر، میتوان اشیای ParamSpec را نیز بهصورت زیر ایجاد کرد:
متغیرهای مشخصات پارامتر عمدتاً برای کمک به بررسیکنندههای نوع ایستا وجود دارند. آنها برای انتقال انواع پارامترهای یک فراخوانیپذیر به فراخوانیپذیر دیگر استفاده میشوند — الگویی رایج در توابع مرتبهی بالاتر و دکوراتورها. آنها تنها زمانی معتبر هستند که در Concatenate، یا بهعنوان اولین آرگومان Callable، یا بهعنوان پارامترهایی برای انواع عام تعریفشده توسط کاربر استفاده شوند. برای اطلاعات بیشتر دربارهی انواع عام، Generic را ببینید.
برای مثال، برای افزودن گزارشگیری پایه به یک تابع، میتوان یک دکوراتور add_logging برای ثبت فراخوانیهای تابع ایجاد کرد. متغیر مشخصه پارامتر به بررسیکننده نوع میگوید که شیء فراخوانیپذیرای که به دکوراتور داده میشود و شیء قابل فراخوانی جدیدی که توسط آن بازگردانده میشود، پارامترهای نوع وابسته به یکدیگر دارند:
from collections.abc import Callable
import logging
def add_logging[T, **P](f: Callable[P, T]) -> Callable[P, T]:
'''A type-safe decorator to add logging to a function.'''
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
logging.info(f'{f.__name__} was called')
return f(*args, **kwargs)
return inner
@add_logging
def add_two(x: float, y: float) -> float:
'''Add two numbers together.'''
return x + y
بدون ParamSpec، سادهترین راه برای حاشیهنویسی این مورد پیشتر، استفاده از یک TypeVar با کران بالایی Callable[..., Any] بود. با این حال این کار دو مشکل ایجاد میکند:
بررسیگر نوع نمیتواند تابع inner را از نظر نوع بررسی کند، زیرا *args و **kwargs باید بهصورت Any نوعدهی شوند.
ممکن است در بدنه دکوراتور add_logging هنگام برگرداندن تابع inner، استفاده از cast() لازم باشد، یا باید به بررسیکننده نوع ایستا گفته شود که return inner را نادیده بگیرد.
-
args¶
-
kwargs¶
از آنجا که ParamSpec هم پارامترهای جایگاهی و هم پارامترهای کلیدواژهای را در بر میگیرد، میتوان از P.args و P.kwargs برای تجزیه یک ParamSpec به کامپوننتهای آن استفاده کرد. P.args نشاندهنده تاپل پارامترهای جایگاهی در یک فراخوانی مشخص است و باید فقط برای حاشیهنویسی *args به کار رود. P.kwargs نشاندهنده نگاشت پارامترهای کلیدواژهای به مقادیرشان در یک فراخوانی مشخص است و باید فقط برای حاشیهنویسی **kwargs به کار رود. هر دو ویژگی مستلزم آن هستند که پارامتر حاشیهنویسیشده در محدوده باشد. در رانتایم، P.args و P.kwargs بهترتیب نمونههایی از ParamSpecArgs و ParamSpecKwargs هستند.
-
__name__¶
نام مشخصهی پارامتر.
-
__covariant__¶
اینکه آیا مشخصات پارامتر صراحتاً به عنوان هموردا علامتگذاری شده است یا خیر.
-
__contravariant__¶
اینکه آیا مشخصات پارامتر صراحتاً به عنوان پادوردا علامتگذاری شده است یا خیر.
-
__infer_variance__¶
اینکه آیا واریانس مشخصات پارامتر باید توسط بررسیکنندههای نوع استنتاج شود یا خیر.
اضافه شده در نسخهی 3.12.
-
__default__¶
مقدار پیشفرض مشخصات پارامتر، یا typing.NoDefault اگر پیشفرضی نداشته باشد.
اضافه شده در نسخهی 3.13.
-
evaluate_default()¶
یک evaluate function متناظر با ویژگی __default__. هنگام فراخوانی مستقیم، این متد تنها از قالب VALUE پشتیبانی میکند، که معادل دسترسی مستقیم به ویژگی __default__ است، اما میتوان شیء متد را به annotationlib.call_evaluate_function() ارسال کرد تا مقدار را در قالبی دیگر ارزیابی کند.
اضافه شده در نسخهی 3.14.
-
has_default()¶
بازمیگرداند که آیا مشخصهی پارامتر (parameter specification) مقدار پیشفرض دارد یا خیر. این معادل بررسی این است که آیا __default__ همان تکنمونه typing.NoDefault نیست، با این تفاوت که ارزیابی مقدار پیشفرض بهصورت تنبل ارزیابیشده را اجباری نمیکند.
اضافه شده در نسخهی 3.13.
متغیرهای مشخصه پارامتر (parameter specification variables) ایجادشده با covariant=True یا contravariant=True میتوانند برای اعلام انواع عام هموردا یا پادوردا (contravariant) استفاده شوند. آرگومان bound نیز پذیرفته میشود، مشابه TypeVar. با این حال، معنای واقعی این کلیدواژهها هنوز تعیین نشده است.
اضافه شده در نسخهی 3.10.
تغییر یافته در نسخهی 3.12: اکنون میتوان مشخصات پارامتر را با استفاده از سینتکس پارامتر نوع معرفیشده در PEP 695 تعریف کرد.
تغییر یافته در نسخهی 3.13: پشتیبانی از مقادیر پیشفرض اضافه شد.
نکته
فقط متغیرهای مشخصه پارامتر تعریفشده در محدوده سراسری را میتوان پیکل کرد.
-
class typing.ParamSpecArgs¶
-
class typing.ParamSpecKwargs¶
ویژگیهای آرگومانها و آرگومانهای کلیدواژهای یک ParamSpec. ویژگی P.args در یک ParamSpec نمونهای از ParamSpecArgs است، و P.kwargs نمونهای از ParamSpecKwargs است. آنها برای دروننگری در رانتایم در نظر گرفته شدهاند و معنای خاصی برای بررسیکنندههای نوع ایستا ندارند.
فراخوانی get_origin() برای هر یک از این اشیاء، ParamSpec اصلی را برمیگرداند:
>>> from typing import ParamSpec, get_origin
>>> P = ParamSpec("P")
>>> get_origin(P.args) is P
True
>>> get_origin(P.kwargs) is P
True
اضافه شده در نسخهی 3.10.
-
class typing.TypeAliasType(name, value, *, type_params=(), qualname=None)¶
نوع نامهای مستعار نوع ایجادشده از طریق دستور type.
مثال:
>>> type Alias = int
>>> type(Alias)
<class 'typing.TypeAliasType'>
اضافه شده در نسخهی 3.12.
-
__name__¶
نام مستعار نوع:
>>> type Alias = int
>>> Alias.__name__
'Alias'
-
__qualname__¶
نام کامل مستعار نوع:
>>> class Class:
... type Alias = int
...
>>> Class.Alias.__qualname__
'Class.Alias'
اضافه شده در نسخهی 3.15.
-
__module__¶
نام ماژولی که نام مستعار نوع در آن تعریف شده است:
>>> type Alias = int
>>> Alias.__module__
'__main__'
این ویژگی قابل نوشتن است.
تغییر یافته در نسخهی 3.15: این ویژگی اکنون قابل نوشتن است.
-
__type_params__¶
پارامترهای نوعِ نام مستعار نوع، یا یک تاپل خالی در صورتی که نام مستعار عام نباشد:
>>> type ListOrSet[T] = list[T] | set[T]
>>> ListOrSet.__type_params__
(T,)
>>> type NotGeneric = int
>>> NotGeneric.__type_params__
()
-
__value__¶
مقدار نام مستعار نوع. این مقدار بهصورت تنبل ارزیابی میشود، بنابراین نامهای بهکاررفته در تعریف نام مستعار تا زمانی که به ویژگی __value__ دسترسی پیدا نشود، حل نمیشوند:
>>> type Mutually = Recursive
>>> type Recursive = Mutually
>>> Mutually
Mutually
>>> Recursive
Recursive
>>> Mutually.__value__
Recursive
>>> Recursive.__value__
Mutually
-
evaluate_value()¶
یک evaluate function متناظر با ویژگی __value__. هنگامی که این متد بهصورت مستقیم فراخوانی شود، فقط از قالب VALUE پشتیبانی میکند، که معادل دسترسی مستقیم به ویژگی __value__ است، اما میتوان شیء متد را به annotationlib.call_evaluate_function() ارسال کرد تا مقدار در قالبی متفاوت ارزیابی شود:
>>> type Alias = undefined
>>> Alias.__value__
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> from annotationlib import Format, call_evaluate_function
>>> Alias.evaluate_value(Format.VALUE)
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
ForwardRef('undefined')
اضافه شده در نسخهی 3.14.
واگشایی
نامهای مستعار نوع از واگشایی ستارهای با استفاده از سینتکس *Alias پشتیبانی میکنند. این معادل استفاده مستقیم از Unpack[Alias] است:
>>> type Alias = tuple[int, str]
>>> type Unpacked = tuple[bool, *Alias]
>>> Unpacked.__value__
tuple[bool, typing.Unpack[Alias]]
اضافه شده در نسخهی 3.14.
سایر دایرکتیوهای خاص¶
این توابع و کلاسها نباید بهطور مستقیم بهعنوان حاشیهنویسی استفاده شوند. هدف موردنظر آنها این است که بلوکهای سازندهای برای ایجاد و اعلان انواع باشند.
-
class typing.NamedTuple¶
نسخهی تایپشدهی collections.namedtuple().
استفاده:
class Employee(NamedTuple):
name: str
id: int
این معادل است با:
Employee = collections.namedtuple('Employee', ['name', 'id'])
برای دادن مقدار پیشفرض به یک فیلد، میتوانید در بدنه کلاس به آن مقدار اختصاص دهید:
class Employee(NamedTuple):
name: str
id: int = 3
employee = Employee('Guido')
assert employee.id == 3
فیلدهای دارای مقدار پیشفرض باید پس از هر فیلد بدون مقدار پیشفرض قرار بگیرند.
میتوان نوع هر نام فیلد را با فراخوانی annotationlib.get_annotations() بر روی کلاس حاصل بازیابی کرد. (نامهای فیلد در ویژگی _fields و مقادیر پیشفرض در ویژگی _field_defaults قرار دارند، که هر دو بخشی از API namedtuple() هستند.)
زیرکلاسهای NamedTuple همچنین میتوانند رشتههای مستندسازی و متدها داشته باشند:
class Employee(NamedTuple):
"""Represents an employee."""
name: str
id: int = 3
def __repr__(self) -> str:
return f'<Employee {self.name}, id={self.id}>'
زیرکلاسهای NamedTuple میتوانند عام باشند:
class Group[T](NamedTuple):
key: T
group: list[T]
استفادهی سازگار با نسخههای پیشین:
# For creating a generic NamedTuple on Python 3.11
T = TypeVar("T")
class Group(NamedTuple, Generic[T]):
key: T
group: list[T]
# A functional syntax is also supported
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
تغییر یافته در نسخهی 3.6: پشتیبانی از سینتکس حاشیهنویسی متغیرها در PEP 526 افزوده شد.
تغییر یافته در نسخهی 3.6.1: پشتیبانی از مقادیر پیشفرض، متدها و رشتهمستندها افزوده شد.
تغییر یافته در نسخهی 3.8: ویژگیهای _field_types و __annotations__ اکنون بهجای نمونههایی از OrderedDict، دیکشنریهای معمولی هستند.
تغییر یافته در نسخهی 3.9: ویژگی _field_types به نفع ویژگی استانداردتر __annotations__ که همان اطلاعات را دارد، حذف شد.
تغییر یافته در نسخهی 3.9: NamedTuple اکنون بهجای کلاس، یک تابع است. هنوز میتوان از آن بهعنوان کلاس پایه استفاده کرد، همانطور که در بالا توضیح داده شد.
تغییر یافته در نسخهی 3.11: پشتیبانی از namedtuples عام افزوده شد.
تغییر یافته در نسخهی 3.14: استفاده از super() (و متغیر بستار با نام __class__) در متدهای زیرکلاسهای NamedTuple پشتیبانی نمیشود و منجر به TypeError میشود.
-
class typing.NewType(name, tp)¶
کلاس کمکی برای ایجاد انواع متمایز با سربار کم.
یک NewType از نظر یک بررسیگر نوع یک نوع متمایز در نظر گرفته میشود. با این حال، در رانتایم، فراخوانی یک NewType آرگومان خود را بدون تغییر برمیگرداند.
استفاده:
UserId = NewType('UserId', int) # Declare the NewType "UserId"
first_user = UserId(1) # "UserId" returns the argument unchanged at runtime
-
__module__¶
نام ماژولی که نوع جدید در آن تعریف شده است.
-
__name__¶
نام نوع جدید.
-
__supertype__¶
نوعی که نوع جدید بر پایهی آن است.
اضافه شده در نسخهی 3.5.2.
تغییر یافته در نسخهی 3.10: NewType اکنون یک کلاس است، نه یک تابع.
-
class typing.Protocol(Generic)¶
کلاس پایه برای کلاسهای پروتکل.
کلاسهای پروتکل به این شکل تعریف میشوند:
class Proto(Protocol):
def meth(self) -> int:
...
چنین کلاسهایی عمدتاً با بررسیکنندههای نوع ایستا استفاده میشوند که زیرنوعدهی ساختاری (نوعدهی اردکی ایستا) را به رسمیت میشناسند، برای مثال:
class C:
def meth(self) -> int:
return 0
def func(x: Proto) -> int:
return x.meth()
func(C()) # Passes static type check
برای جزئیات بیشتر PEP 544 را ببینید. کلاسهای پروتکل که با @runtime_checkable آراسته شدهاند (بعداً توضیح داده میشود) بهعنوان پروتکلهای رانتایم سادهای عمل میکنند که تنها وجود ویژگیهای دادهشده را بررسی میکنند و امضاهای نوعی آنها را نادیده میگیرند. کلاسهای پروتکل بدون این دکوراتور نمیتوانند بهعنوان آرگومان دوم isinstance() یا issubclass() استفاده شوند.
کلاسهای Protocol میتوانند عام باشند، برای مثال:
class GenProto[T](Protocol):
def meth(self) -> T:
...
در کدی که باید با Python 3.11 یا قدیمیتر سازگار باشد، میتوان پروتکلهای عام (generic Protocols) را بهصورت زیر نوشت:
T = TypeVar("T")
class GenProto(Protocol[T]):
def meth(self) -> T:
...
منسوخ شده از نسخهی 3.15, در نسخهی 3.20 حذف خواهد شد: انجام بررسیهای isinstance() و issubclass() روی کلاسهای پروتکلی که صریحاً با runtime_checkable() تزئین نشدهاند اما از یک کلاس پروتکل دارای قابلیت بررسی در رانتایم ارثبری میکنند، منسوخ شده است. این کار در پایتون ۳.۲۰ یک TypeError پرتاب خواهد کرد.
-
@typing.runtime_checkable¶
یک کلاس پروتکل را بهعنوان پروتکل رانتایم علامتگذاری میکند.
چنین پروتکلی را میتوان با isinstance() و issubclass() به کار برد. این امر یک بررسی ساختاری ساده را ممکن میسازد، که بسیار شبیه به «اسبهای تکفن» در collections.abc مانند Iterable است. برای مثال:
@runtime_checkable
class Closable(Protocol):
def close(self): ...
assert isinstance(open('/some/file'), Closable)
@runtime_checkable
class Named(Protocol):
name: str
import threading
assert isinstance(threading.Thread(name='Bob'), Named)
قابلیت بررسی در رانتایم پروتکلها ارثبری نمیشود. زیرکلاس یک پروتکل با قابلیت بررسی در رانتایم تنها در صورتی قابلیت بررسی در رانتایم را دارد که صریحاً به همین شکل علامتگذاری شده باشد، صرفنظر از سلسلهمراتب کلاس:
@runtime_checkable
class Iterable(Protocol):
def __iter__(self): ...
# Without @runtime_checkable, Reversible would no longer be runtime-checkable.
@runtime_checkable
class Reversible(Iterable, Protocol):
def __reversed__(self): ...
این دکوراتور هنگام اعمال روی یک کلاس غیرپروتکلی، استثنای TypeError را پرتاب میکند.
نکته
runtime_checkable فقط وجود متدها یا ویژگیهای مورد نیاز را بررسی میکند، نه امضای نوع یا نوع آنها را. برای مثال، ssl.SSLObject یک کلاس است، بنابراین در بررسی issubclass() در برابر Callable قبول میشود. با این حال، متد ssl.SSLObject.__init__ فقط برای پرتاب یک TypeError با پیامی آگاهکنندهتر وجود دارد، در نتیجه فراخوانی (نمونهسازی) ssl.SSLObject را غیرممکن میسازد.
نکته
بررسی isinstance() در برابر یک پروتکل قابلبررسی در رانتایم میتواند در مقایسه با بررسی isinstance() در برابر یک کلاس غیرپروتکلی بهطور غافلگیرکنندهای کند باشد. برای بررسیهای ساختاری در کد حساس به عملکرد، استفاده از الگوهای جایگزین مانند فراخوانیهای hasattr() را در نظر بگیرید.
تغییر یافته در نسخهی 3.12: پیادهسازی داخلی بررسیهای isinstance() در برابر پروتکلهای قابل بررسی در رانتایم، اکنون از inspect.getattr_static() برای جستوجوی ویژگیها استفاده میکند (پیش از این، hasattr() استفاده میشد). در نتیجه، برخی اشیایی که پیشتر نمونههایی از یک پروتکل قابل بررسی در رانتایم در نظر گرفته میشدند، ممکن است دیگر در Python 3.12+ نمونههای آن پروتکل در نظر گرفته نشوند، و برعکس. بعید است بیشتر کاربران تحت تأثیر این تغییر قرار بگیرند.
تغییر یافته در نسخهی 3.12: اعضای یک پروتکل قابلبررسی در رانتایم، اکنون بهمحض ایجاد کلاس، در رانتایم «فریز» در نظر گرفته میشوند. افزودن ویژگیها بهصورت مانکیپچ (monkey-patching) به یک پروتکل قابلبررسی در رانتایم همچنان کار میکند، اما هیچ تأثیری بر بررسیهای isinstance() برای مقایسهی اشیاء با آن پروتکل نخواهد داشت. برای جزئیات بیشتر، تازههای پایتون 3.12 را ببینید.
منسوخ شده از نسخهی 3.15, در نسخهی 3.20 حذف خواهد شد: انجام بررسیهای isinstance() و issubclass() روی کلاسهای پروتکلی که صریحاً با runtime_checkable() تزئین نشدهاند اما از یک کلاس پروتکل دارای قابلیت بررسی در رانتایم ارثبری میکنند، منسوخ شده است. این کار در پایتون ۳.۲۰ یک TypeError پرتاب خواهد کرد.
-
class typing.TypedDict(dict)¶
ساختاری ویژه برای افزودن راهنماهای نوع به یک دیکشنری. در رانتایم، «نمونههای TypedDict» صرفاً dicts هستند.
TypedDict یک نوع دیکشنری را تعریف میکند که انتظار دارد همه نمونههای آن دارای مجموعهای مشخص از کلیدها باشند، که هر کلید با مقداری از یک نوع سازگار مرتبط است. این انتظار در رانتایم بررسی نمیشود، بلکه فقط توسط بررسیکنندههای نوع اعمال میشود. کاربرد:
class Point2D(TypedDict):
x: int
y: int
label: str
a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK
b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check
assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
یک روش جایگزین برای ایجاد TypedDict، استفاده از سینتکس فراخوانی تابع است. آرگومان دوم باید یک dict لفظی باشد:
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
این سینتکس تابعی به شما امکان میدهد کلیدهایی را تعریف کنید که شناسههای معتبر نیستند، برای مثال به این دلیل که کلیدواژه هستند یا حاوی خط تیره هستند، یا زمانی که نام کلیدها نباید مانند نامهای خصوصی عادی دستکاری شوند:
# raises SyntaxError
class Point2D(TypedDict):
in: int # 'in' is a keyword
x-y: int # name with hyphens
class Definition(TypedDict):
__schema: str # mangled to `_Definition__schema`
# OK, functional syntax
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
Definition = TypedDict('Definition', {'__schema': str}) # not mangled
بهطور پیشفرض، تمام کلیدها باید در یک TypedDict وجود داشته باشند. میتوان کلیدهای منفرد را با استفاده از NotRequired بهعنوان غیرضروری علامتگذاری کرد:
class Point2D(TypedDict):
x: int
y: int
label: NotRequired[str]
# Alternative syntax
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': NotRequired[str]})
این بدان معناست که یک Point2D TypedDict میتواند فاقد کلید label باشد.
همچنین میتوان با تعیین مقدار False برای totality، همهی کلیدها را بهطور پیشفرض بهعنوان غیرالزامی علامتگذاری کرد:
class Point2D(TypedDict, total=False):
x: int
y: int
# Alternative syntax
Point2D = TypedDict('Point2D', {'x': int, 'y': int}, total=False)
این بدان معناست که یک TypedDict از نوع Point2D میتواند فاقد هر یک از کلیدها باشد. انتظار میرود بررسیکننده نوع فقط از مقدار لفظی False یا True بهعنوان مقدار آرگومان total پشتیبانی کند. True مقدار پیشفرض است و تمام آیتمهای تعریفشده در بدنه کلاس را الزامی میکند.
میتوان تکتک کلیدهای یک TypedDict با total=False را با استفاده از Required بهعنوان الزامی علامتگذاری کرد:
class Point2D(TypedDict, total=False):
x: Required[int]
y: Required[int]
label: str
# Alternative syntax
Point2D = TypedDict('Point2D', {
'x': Required[int],
'y': Required[int],
'label': str
}, total=False)
یک نوع TypedDict میتواند با استفاده از سینتکس مبتنی بر کلاس، از یک یا چند نوع TypedDict دیگر به ارث ببرد. استفاده:
class Point3D(Point2D):
z: int
Point3D سه آیتم دارد: x، y و z. معادل این تعریف است:
class Point3D(TypedDict):
x: int
y: int
z: int
به طور پیشفرض، یک TypedDict باز است، به این معنی که ممکن است حاوی کلیدهای اضافی در رانتایم فراتر از کلیدهای تعریفشده در بدهی کلاس باشد. آرگومان کلاس closed میتواند برای کنترل این موضوع استفاده شود؛ اگر closed=True باشد، TypedDict نمیتواند حاوی کلیدهای اضافی باشد.
class ClosedPoint(TypedDict, closed=True):
x: int
y: int
class ClosedPoint3D(ClosedPoint): # type checker error: cannot add keys to a closed TypedDict
z: int
تنظیم صریح closed=False رفتار پیشفرضِ باز را درخواست میکند. اگر آرگومان ارسال نشود، این وضعیت از کلاس والد به ارث برده میشود.
علاوه بر باز یا بسته بودن، یک TypedDict را میتوان به گونهای پیکربندی کرد که آیتمهای اضافی داشته باشد. اگر آرگومان کلاس extra_items روی یک نوع تنظیم شود، TypedDict میتواند کلیدهای اضافی دلخواهی را شامل شود، اما مقادیر آن کلیدها باید از نوع مشخصشده باشند.
class ExtraItemsPoint(TypedDict, extra_items=int):
x: int
y: int
point: ExtraItemsPoint = {'x': 1, 'y': 2, 'anything': 3} # OK
آرگومان extra_items همچنین از طریق زیرکلاسسازی به ارث برده میشود. این آرگومان به طور پیشفرض تنظیم نشده است و نمیتوان آن را به همراه آرگومان closed استفاده کرد.
یک TypedDict نمیتواند از کلاسی غیر TypedDict ارثبری کند، بهجز Generic. برای مثال:
class X(TypedDict):
x: int
class Y(TypedDict):
y: int
class Z(object): pass # A non-TypedDict class
class XY(X, Y): pass # OK
class XZ(X, Z): pass # raises TypeError
یک TypedDict میتواند عام باشد:
class Group[T](TypedDict):
key: T
group: list[T]
برای ایجاد یک TypedDict عام که با Python 3.11 یا پایینتر سازگار است، بهصراحت از Generic ارثبری کنید:
T = TypeVar("T")
class Group(TypedDict, Generic[T]):
key: T
group: list[T]
یک TypedDict را میتوان از طریق annotationlib.get_annotations() (برای اطلاعات بیشتر درباره بهترین شیوههای حاشیهنویسی به بهترین شیوههای حاشیهنویسی مراجعه کنید) و ویژگیهای زیر دروننگری کرد:
-
__total__¶
Point2D.__total__ مقدار آرگومان total را میدهد. مثال:
>>> from typing import TypedDict
>>> class Point2D(TypedDict): pass
>>> Point2D.__total__
True
>>> class Point2D(TypedDict, total=False): pass
>>> Point2D.__total__
False
>>> class Point3D(Point2D): pass
>>> Point3D.__total__
True
این ویژگی فقط مقدار آرگومان total برای کلاس TypedDict جاری را نشان میدهد، نه اینکه آیا این کلاس از نظر معنایی total است یا خیر. برای مثال، یک TypedDict که __total__ آن روی True تنظیم شده است، ممکن است کلیدهایی داشته باشد که با NotRequired علامتگذاری شدهاند، یا ممکن است از یک TypedDict دیگر با total=False ارثبری کند. بنابراین، بهطور کلی بهتر است برای دروننگری از __required_keys__ و __optional_keys__ استفاده کنید.
-
__required_keys__¶
-
-
__optional_keys__¶
Point2D.__required_keys__ و Point2D.__optional_keys__ بهترتیب اشیای frozenset شامل کلیدهای الزامی و غیرالزامی را بازمیگردانند.
کلیدهای علامتگذاریشده با Required همیشه در __required_keys__ ظاهر میشوند و کلیدهای علامتگذاریشده با NotRequired همیشه در __optional_keys__ ظاهر میشوند.
برای حفظ سازگاری با Python 3.10 و نسخههای پایینتر، همچنین میتوان از وراثت برای تعریف هر دو دسته کلید الزامی و غیرالزامی در یک TypedDict واحد استفاده کرد. این کار با تعریف یک TypedDict با یک مقدار برای آرگومان total و سپس وراثت از آن در یک TypedDict دیگر با مقداری متفاوت برای total انجام میشود:
>>> class Point2D(TypedDict, total=False):
... x: int
... y: int
...
>>> class Point3D(Point2D):
... z: int
...
>>> Point3D.__required_keys__ == frozenset({'z'})
True
>>> Point3D.__optional_keys__ == frozenset({'x', 'y'})
True
نکته
اگر از from __future__ import annotations استفاده شود یا اگر حاشیهنویسیها بهصورت رشته ارائه شوند، حاشیهنویسیها هنگام تعریف TypedDict ارزیابی نمیشوند. بنابراین، ممکن است دروننگری رانتایمی که __required_keys__ و __optional_keys__ به آن متکی هستند، بهدرستی کار نکند و مقادیر ویژگیها نادرست باشند.
-
__readonly_keys__¶
یک frozenset شامل نام تمام کلیدهای فقطخواندنی. کلیدها در صورتی فقطخواندنی هستند که دارای مشخصکننده (qualifier) ReadOnly باشند.
اضافه شده در نسخهی 3.13.
-
__mutable_keys__¶
یک frozenset حاوی نام تمام کلیدهای تغییرپذیر. کلیدها در صورتی تغییرپذیر هستند که فاقد مشخصکننده ReadOnly باشند.
اضافه شده در نسخهی 3.13.
-
__closed__¶
مقدار آرگومان کلاس closed. این مقدار میتواند True، False یا None باشد.
-
__extra_items__¶
مقدار آرگومان کلاس extra_items. این مقدار میتواند یک نوع معتبر یا NoExtraItems باشد.
برای مثالهای بیشتر و قوانین دقیق، بخش TypedDict را در مستندات typing ببینید.
تغییر یافته در نسخهی 3.9: TypedDict اکنون بهجای کلاس، یک تابع است. هنوز هم میتوان از آن بهعنوان پایهی یک کلاس استفاده کرد، همانطور که در بالا توضیح داده شد.
تغییر یافته در نسخهی 3.11: پشتیبانی از TypedDictهای عام افزوده شد.
تغییر یافته در نسخهی 3.13: پشتیبانی از روش آرگومان کلیدواژهای برای ایجاد TypedDicts حذف شد.
تغییر یافته در نسخهی 3.13: پشتیبانی از مشخصکننده ReadOnly اضافه شد. به PEP 705 مراجعه کنید.
تغییر یافته در نسخهی 3.15: پشتیبانی از آرگومانهای کلاس closed و extra_items اضافه شد. نگاه کنید به PEP 728.
پروتکلها¶
پروتکلهای زیر توسط ماژول typing ارائه شدهاند. همهی آنها با دکوراتور @runtime_checkable آراسته شدهاند.
-
class typing.SupportsAbs¶
یک پروتکل با یک متد انتزاعی __abs__ که از نظر نوع بازگشتی، هموردا است.
-
class typing.SupportsBytes¶
پروتکلی با یک متد انتزاعی __bytes__.
-
class typing.SupportsComplex¶
یک پروتکل با یک متد انتزاعی __complex__.
-
class typing.SupportsFloat¶
یک پروتکل با یک متد انتزاعی __float__.
-
class typing.SupportsIndex¶
یک پروتکل با یک متد انتزاعی __index__.
-
class typing.SupportsInt¶
پروتکلی با یک متد انتزاعی __int__.
-
class typing.SupportsRound¶
یک پروتکل با یک متد انتزاعی __round__ که نوع بازگشتی آن هموردا است.
ABCها و پروتکلها برای کار با I/O¶
-
class typing.IO[AnyStr]¶
-
class typing.TextIO¶
-
class typing.BinaryIO¶
کلاس عام IO[AnyStr] و زیرکلاسهای آن، TextIO(IO[str]) و BinaryIO(IO[bytes])، نشاندهندهی انواع جریانهای ورودی/خروجی هستند، مانند جریانهایی که توسط open() بازگردانده میشوند. لطفاً توجه داشته باشید که این کلاسها پروتکل نیستند و رابط آنها نسبتاً گسترده است.
پروتکلهای io.Reader و io.Writer جایگزین سادهتری برای انواع آرگومان ارائه میدهند، هنگامی که بهترتیب فقط به متدهای read() یا write() دسترسی دارید:
def read_and_write(reader: Reader[str], writer: Writer[bytes]):
data = reader.read()
writer.write(data.encode())
همچنین برای تکرار روی سطرهای یک جریان ورودی، استفاده از collections.abc.Iterable را در نظر بگیرید:
def read_config(stream: Iterable[str]):
for line in stream:
...
توابع و دکوراتورها¶
-
typing.cast(typ, val)¶
یک مقدار را به یک نوع تبدیل کنید.
این، مقدار را بدون تغییر برمیگرداند. برای بررسیگر نوع، این نشان میدهد که مقدار بازگشتی، نوع تعیینشده را دارد، اما در رانتایم عمداً هیچ چیزی را بررسی نمیکنیم (میخواهیم این تا حد ممکن سریع باشد).
-
typing.assert_type(val, typ, /)¶
از یک بررسیکننده نوع ایستا بخواهید تأیید کند که نوع استنتاجشده برای val، typ است.
در رانتایم این هیچ کاری انجام نمیدهد: اولین آرگومان را بدون تغییر و بدون هیچگونه بررسی یا عوارض جانبی برمیگرداند، صرفنظر از نوع واقعی آرگومان.
هنگامی که یک بررسیکننده نوع ایستا با فراخوانی assert_type() مواجه میشود، اگر مقدار از نوع مشخصشده نباشد، خطایی را نشان میدهد:
def greet(name: str) -> None:
assert_type(name, str) # OK, inferred type of `name` is `str`
assert_type(name, int) # type checker error
این تابع برای اطمینان از هماهنگی درک بررسیکننده نوع از یک اسکریپت با قصد توسعهدهنده مفید است:
def complex_function(arg: object):
# Do some complex type-narrowing logic,
# after which we hope the inferred type will be `int`
...
# Test whether the type checker correctly understands our function
assert_type(arg, int)
اضافه شده در نسخهی 3.11.
-
typing.assert_never(arg, /)¶
از یک بررسیگر نوع ایستا (static type checker) بخواهید تأیید کند که یک خط کد غیرقابلدسترس است.
مثال:
def int_or_str(arg: int | str) -> None:
match arg:
case int():
print("It's an int")
case str():
print("It's a str")
case _ as unreachable:
assert_never(unreachable)
در اینجا، حاشیهنویسیها به بررسیگر نوع اجازه میدهند استنباط کند که آخرین حالت هرگز نمیتواند اجرا شود، زیرا arg یا یک int است یا یک str، و هر دو گزینه در حالتهای پیشین پوشش داده شدهاند.
اگر یک بررسیکننده نوع تشخیص دهد که فراخوانی assert_never() قابلدسترس است، خطایی نشان میدهد. برای مثال، اگر حاشیهنویسی نوع (type annotation) برای arg در عوض int | str | float باشد، بررسیکننده نوع خطایی را نشان میدهد که نشان میدهد unreachable از نوع float است. برای این که فراخوانی assert_never بررسی نوع را بگذراند، نوع استنتاجشده آرگومان دادهشده باید نوع پایین (bottom type)، یعنی Never، و نه هیچ چیز دیگری باشد.
در رانتایم، این هنگام فراخوانی یک استثنا پرتاب میکند.
اضافه شده در نسخهی 3.11.
-
typing.reveal_type(obj, /)¶
از یک بررسیگر نوع ایستا بخواهید نوع استنتاجشدهی یک عبارت را آشکار کند.
هنگامی که یک بررسیکننده نوع ایستا با فراخوانی این تابع مواجه میشود، یک تشخیص همراه با نوع استنتاجشده آرگومان نشان میدهد. برای مثال:
x: int = 1
reveal_type(x) # Revealed type is "builtins.int"
این میتواند زمانی مفید باشد که بخواهید چگونگی برخورد بررسیکننده نوع خود با یک قطعه کد خاص را اشکالزدایی کنید.
در رانتایم، این تابع نوع رانتایمی آرگومان خود را در sys.stderr چاپ میکند و آرگومان را بدون تغییر برمیگرداند (که اجازه میدهد فراخوانی درون یک عبارت به کار رود):
x = reveal_type(1) # prints "Runtime type is int"
print(x) # prints "1"
توجه داشته باشید که نوع رانتایم ممکن است با نوعی که یک بررسیکننده نوع بهصورت ایستا استنتاج میکند متفاوت باشد (خاصتر یا عامتر باشد).
بیشتر بررسیکنندههای نوع از reveal_type() در هر جایی پشتیبانی میکنند، حتی اگر این نام از typing ایمپورت نشده باشد. با این حال، ایمپورت کردن این نام از typing به کد شما اجازه میدهد بدون خطاهای رانتایم اجرا شود و منظور را واضحتر بیان میکند.
اضافه شده در نسخهی 3.11.
-
@typing.dataclass_transform(*, eq_default=True, order_default=False, kw_only_default=False, frozen_default=False, field_specifiers=(), **kwargs)¶
دکوراتوری برای علامتگذاری یک شیء بهعنوان ارائهدهندهی رفتاری شبیه به dataclass.
میتوان از @dataclass_transform برای دکور کردن یک کلاس، فراکلاس یا تابعی که خود یک دکوراتور است استفاده کرد. وجود @dataclass_transform() به یک بررسیگر نوع ایستا میگوید که شیء دکورشده «جادو»یی در رانتایم انجام میدهد که یک کلاس را به شیوهای مشابه @dataclasses.dataclass دگرگون میکند.
نمونه استفاده با یک تابع دکوراتور:
@dataclass_transform()
def create_model[T](cls: type[T]) -> type[T]:
...
return cls
@create_model
class CustomerModel:
id: int
name: str
بر روی یک کلاس پایه:
@dataclass_transform()
class ModelBase: ...
class CustomerModel(ModelBase):
id: int
name: str
در یک فراکلاس:
@dataclass_transform()
class ModelMeta(type): ...
class ModelBase(metaclass=ModelMeta): ...
class CustomerModel(ModelBase):
id: int
name: str
بررسیکنندههای نوع با کلاسهای CustomerModel تعریفشده در بالا، مشابه کلاسهای ایجادشده با @dataclasses.dataclass رفتار خواهند کرد. برای مثال، بررسیکنندههای نوع فرض خواهند کرد که این کلاسها متدهای __init__ دارند که id و name را میپذیرند.
کلاس، فراکلاس یا تابع دکوریتشده ممکن است آرگومانهای بولی زیر را بپذیرد که بررسیکنندههای نوع فرض خواهند کرد همان اثری را دارند که بر روی دکوراتور @dataclasses.dataclass خواهند داشت: init، eq، order، unsafe_hash، frozen، match_args، kw_only و slots. باید بتوان مقدار این آرگومانها (True یا False) را بهصورت ایستا ارزیابی کرد.
میتوان از آرگومانهای دکوراتور @dataclass_transform برای سفارشیسازی رفتارهای پیشفرض کلاس، فراکلاس یا تابع دکوراتشده استفاده کرد:
- پارامترها:
eq_default (bool) -- نشان میدهد که اگر فراخواننده پارامتر eq را حذف کند، فرض میشود مقدار آن True یا False باشد. مقدار پیشفرض آن True است.
order_default (bool) -- نشان میدهد که اگر پارامتر order توسط فراخواننده ذکر نشود، فرض میشود مقدار آن True باشد یا False. پیشفرض False است.
kw_only_default (bool) -- نشان میدهد که اگر فراخواننده پارامتر kw_only را حذف کند، این پارامتر True فرض میشود یا False. مقدار پیشفرض False است.
frozen_default (bool) -- نشان میدهد که در صورت حذف پارامتر frozen توسط فراخواننده، آیا True فرض میشود یا False. پیشفرض False است. .. versionadded:: 3.12
field_specifiers (tuple[Callable[..., Any], ...]) -- فهرست ثابتی از کلاسها یا توابع پشتیبانیشده را مشخص میکند که فیلدها را توصیف میکنند، مشابه dataclasses.field(). پیشفرض آن () است.
**kwargs (Any) -- سایر آرگومانهای کلیدواژهای دلخواه پذیرفته میشوند تا امکان گسترشهای احتمالی در آینده فراهم شود.
بررسیکنندههای نوع، پارامترهای اختیاری زیر را در مشخصکنندههای فیلد شناسایی میکنند:
پارامترهای بهرسمیت شناختهشده برای مشخصکنندههای فیلد¶
نام پارامتر |
توضیحات |
init
|
نشان میدهد که آیا فیلد باید در متد __init__ ساختهشده گنجانده شود یا خیر. اگر مشخص نشده باشد، پیشفرض init برابر True است. |
default
|
مقدار پیشفرض فیلد را فراهم میکند. |
default_factory
|
یک کالبک رانتایم فراهم میکند که مقدار پیشفرض فیلد را برمیگرداند. اگر هیچکدام از default و default_factory مشخص نشده باشند، فرض میشود که فیلد مقدار پیشفرض ندارد و باید هنگام نمونهسازی کلاس، مقداری برای آن فراهم شود. |
factory
|
نام مستعاری برای پارامتر default_factory در مشخصکنندههای فیلد. |
kw_only
|
نشان میدهد که فیلد باید بهعنوان فقط کلیدواژهای علامتگذاری شود یا خیر. اگر True باشد، فیلد فقط کلیدواژهای خواهد بود. اگر False باشد، فقط کلیدواژهای نخواهد بود. اگر تعیین نشده باشد، مقدار پارامتر kw_only در شیء آراستهشده با @dataclass_transform استفاده میشود، یا اگر آن هم تعیین نشده باشد، مقدار kw_only_default در @dataclass_transform استفاده میشود. |
alias
|
نام جایگزینی برای فیلد فراهم میکند. این نام جایگزین در متد __init__ تولیدشده استفاده میشود. |
در رانتایم، این دکوراتور آرگومانهای خود را در ویژگی __dataclass_transform__ روی شیء دکوریتشده ثبت میکند. هیچ اثر دیگری در رانتایم ندارد.
برای جزئیات بیشتر، PEP 681 را ببینید.
اضافه شده در نسخهی 3.11.
-
@typing.overload¶
دکوراتور برای ایجاد توابع و متدهای سربارگذاریشده (overloaded).
دکوراتور @overload امکان توصیف توابع و متدهایی را فراهم میکند که از چندین ترکیب متفاوت از انواع آرگومان پشتیبانی میکنند. پس از مجموعهای از تعاریف آراستهشده با دکوراتور @overload، باید دقیقاً یک تعریف آراستهنشده با دکوراتور @overload (برای همان تابع/متد) بیاید.
تعاریف دکورشده با @overload فقط برای بررسیکننده نوع در نظر گرفته شدهاند، زیرا تعریف بدون دکوراتور @overload آنها را بازنویسی میکند. در مقابل، تعریف بدون دکوراتور @overload در رانتایم استفاده میشود، اما باید از سوی بررسیکننده نوع نادیده گرفته شود. در رانتایم، فراخوانی مستقیم یک تابع دکورشده با @overload، NotImplementedError را پرتاب میکند.
مثالی از سربارگذاری (overload) که نوع دقیقتری را نسبت به آنچه میتوان با استفاده از یک اجتماع (union) یا یک متغیر نوع بیان کرد، ارائه میدهد:
@overload
def process(response: None) -> None:
...
@overload
def process(response: int) -> tuple[int, str]:
...
@overload
def process(response: bytes) -> str:
...
def process(response):
... # actual implementation goes here
برای جزئیات بیشتر و مقایسه با سایر معانی نوعدهی، PEP 484 را ببینید.
تغییر یافته در نسخهی 3.11: اکنون میتوان توابع سربارگذاریشده (overloaded) را در رانتایم با استفاده از get_overloads() دروننگری کرد.
-
typing.get_overloads(func)¶
دنبالهای از تعاریف آراستهشده با دکوراتور @overload برای func برمیگرداند.
func شیء تابع برای پیادهسازی تابع سربارگذاریشده (overload) است. برای مثال، با توجه به تعریف process در مستندات @overload، get_overloads(process) دنبالهای از سه شیء تابع برای سه اورلود تعریفشده را برمیگرداند. اگر برای تابعی بدون اورلود فراخوانی شود، get_overloads() دنبالهای خالی را برمیگرداند.
میتوان از get_overloads() برای دروننگری یک تابع سربارگذاریشده (overloaded function) در رانتایم استفاده کرد.
اضافه شده در نسخهی 3.11.
-
typing.clear_overloads()¶
تمام سربارگذاریهای (overloads) رجیستری داخلی را پاک میکند.
این میتواند برای آزادسازی حافظهی استفادهشده توسط رجیستری به کار رود.
اضافه شده در نسخهی 3.11.
-
@typing.final¶
دکوراتوری برای مشخص کردن متدهای نهایی و کلاسهای نهایی.
اعمال دکوراتور @final بر یک متد، به یک بررسیکننده نوع نشان میدهد که نمیتوان آن متد را در یک زیرکلاس بازنویسی کرد. اعمال دکوراتور @final بر یک کلاس، نشان میدهد که نمیتوان از آن زیرکلاس ساخت.
برای مثال:
class Base:
@final
def done(self) -> None:
...
class Sub(Base):
def done(self) -> None: # Error reported by type checker
...
@final
class Leaf:
...
class Other(Leaf): # Error reported by type checker
...
هیچ بررسیای در رانتایم برای این ویژگیها انجام نمیشود. برای جزئیات بیشتر PEP 591 را ببینید.
تغییر یافته در نسخهی 3.11: دکوراتور اکنون تلاش میکند ویژگی __final__ را روی شیء دکوریتشده به True تنظیم کند. بنابراین، میتوان در رانتایم از بررسیای مانند if getattr(obj, "__final__", False) برای تعیین اینکه آیا یک شیء obj بهعنوان نهایی علامتگذاری شده است استفاده کرد. اگر شیء دکوریتشده از تنظیم ویژگیها پشتیبانی نکند، دکوراتور شیء را بدون تغییر و بدون پرتاب استثنا برمیگرداند.
-
@typing.no_type_check¶
دکوراتوری برای نشان دادن اینکه حاشیهنویسیها راهنماییهای نوع نیستند.
این بهعنوان یک دکوراتور، آراینده برای کلاس یا تابع عمل میکند. در صورت استفاده برای یک کلاس، بهصورت بازگشتی به تمام متدها و کلاسهایی که در آن کلاس تعریف شدهاند اعمال میشود (اما به متدهایی که در کلاسهای والد یا زیرکلاسهای آن تعریف شدهاند اعمال نمیشود). بررسیکنندههای نوع تمام حاشیهنویسیهارا در یک تابع یا کلاس دارای این دکوراتور نادیده میگیرند.
@no_type_check شیء دکوریتشده را بهصورت درجا تغییر میدهد.
-
@typing.override¶
دکوراتوری برای نشان دادن این که یک متد در زیرکلاس برای بازنویسی یک متد یا ویژگی در ابرکلاس در نظر گرفته شده است.
بررسیکنندههای نوع باید در صورتی خطایی را نشان بدهند که یک متد آراستهشده با @override، در واقع هیچ چیزی را بازنویسی نکند. این امر به پیشگیری از اشکالهایی کمک میکند که ممکن است هنگامی رخ دهند که یک کلاس پایه بدون تغییری معادل در یک کلاس فرزند تغییر داده شود.
برای مثال:
class Base:
def log_status(self) -> None:
...
class Sub(Base):
@override
def log_status(self) -> None: # Okay: overrides Base.log_status
...
@override
def done(self) -> None: # Error reported by type checker
...
هیچ بررسیای در رانتایم برای این ویژگی انجام نمیشود.
دکوراتور تلاش میکند ویژگی __override__ را روی شیء دکوراتشده به True تنظیم کند. بنابراین، میتوان از بررسیای مانند if getattr(obj, "__override__", False) در رانتایم استفاده کرد تا تعیین شود که آیا شیء obj بهعنوان بازنویسی علامتگذاری شده است یا خیر. اگر شیء دکوراتشده از تنظیم ویژگیها پشتیبانی نکند، دکوراتور شیء را بدون تغییر و بدون پرتاب استثنا برمیگرداند.
برای جزئیات بیشتر به PEP 698 مراجعه کنید.
اضافه شده در نسخهی 3.12.
-
@typing.disjoint_base¶
دکوراتوری برای علامتگذاری یک کلاس به عنوان پایه مجزا.
بررسیکنندههای نوع اجازه نمیدهند که کلاسهای فرزند یک پایهی مجزا C از پایههای مجزای دیگری که کلاسهای والد یا فرزند C نیستند، ارثبری کنند.
برای مثال:
@disjoint_base
class Disjoint1: pass
@disjoint_base
class Disjoint2: pass
class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error
بررسیکنندههای نوع میتوانند از دانشِ پایههای مجزا برای تشخیص کد دستنیافتنی و تعیین زمان همپوشانی دو نوع استفاده کنند.
مفهوم متناظر در رانتایم، پایهی صلب است (نگاه کنید به وراثت چندگانه). کلاسهایی که در رانتایم پایههای صلبی هستند را میتوان با @disjoint_base در پروندههای stub علامتگذاری کرد. کاربران همچنین ممکن است کلاسهای دیگر را به عنوان پایههای مجزا علامتگذاری کنند تا به بررسیکنندههای نوع نشان دهند که ارثبری چندگانه با سایر پایههای مجزا نباید مجاز باشد.
توجه داشته باشید که مفهوم پایهی صلب یک جزئیات پیادهسازی سیپایتون است و مجموعه دقیق کلاسهای کتابخانهی استاندارد که در رانتایم پایههای مجزایی هستند ممکن است در نسخههای آیندهی پایتون تغییر کند.
اضافه شده در نسخهی 3.15.
-
@typing.type_check_only¶
دکوراتوری برای علامتگذاری یک کلاس یا تابع بهعنوان غیرقابلدسترس در رانتایم.
این دکوراتور به خودی خود در رانتایم در دسترس نیست. این دکوراتور عمدتاً برای علامتگذاری کلاسهایی در نظر گرفته شده است که در پروندههای stub نوع (type stub files) تعریف شدهاند، در صورتی که یک پیادهسازی، نمونهای از یک کلاس خصوصی را برگرداند:
@type_check_only
class Response: # private or not available at runtime
code: int
def get_header(self, name: str) -> str: ...
def fetch_response() -> Response: ...
توجه داشته باشید که برگرداندن نمونههای کلاسهای خصوصی توصیه نمیشود. معمولاً بهتر است چنین کلاسهایی عمومی شوند.
ابزارهای کمکی دروننگری¶
-
typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False, *, format=Format.VALUE)¶
یک دیکشنری حاوی راهنماییهای نوع برای یک تابع، متد، ماژول، شیء کلاس، یا سایر اشیاء فراخوانیپذیر برمیگرداند.
این معمولاً همان annotationlib.get_annotations() است، اما این تابع تغییرات زیر را در دیکشنری حاشیهنویسیها اعمال میکند:
ارجاعهای پیشرو که بهصورت رشتههای لفظی یا اشیای ForwardRef کدگذاری شدهاند، با ارزیابی آنها در globalns، localns و (در صورت لزوم) فضای نام پارامتر نوعobj رسیدگی میشوند. اگر globalns یا localns داده نشده باشد، دیکشنریهای فضای نام مناسب از obj استنتاج میشوند.
None با types.NoneType جایگزین میشود.
اگر @no_type_check به obj اعمال شده باشد، یک دیکشنری خالی برگردانده میشود.
اگر obj یک کلاس C باشد، تابع دیکشنریای را برمیگرداند که حاشیهگذاریهای کلاسهای پایهی C را با حاشیهگذاریهایی که مستقیماً روی C قرار دارند، ادغام میکند. این کار با پیمایش C.__mro__ و ترکیب تدریجی حاشیهگذاریها هر کلاس پایه انجام میشود. حاشیهگذاریهای کلاسهایی که زودتر در method resolution order ظاهر میشوند، همیشه بر حاشیهگذاریهای کلاسهایی که دیرتر در ترتیب حل متد ظاهر میشوند، اولویت دارند.
این تابع بهصورت بازگشتی تمام موارد Annotated[T, ...]، Required[T]، NotRequired[T] و ReadOnly[T] را با T جایگزین میکند، مگر اینکه include_extras روی True تنظیم شده باشد (برای اطلاعات بیشتر Annotated را ببینید).
نکته
اگر از Format.VALUE استفاده شود و هرگونه ارجاع پیشرو در حاشیهنویسیهای obj قابل حل نباشد، استثنای NameError پرتاب میشود. برای مثال، این ممکن است برای نامهایی رخ دهد که ذیل if TYPE_CHECKING ایمپورتشدهاند. بهطور کلیتر، اگر یک حاشیهنویسی حاوی کد نامعتبر پایتون باشد، ممکن است هر نوع استثنایی پرتاب شود.
نکته
فراخوانی get_type_hints() روی یک نمونه پشتیبانی نمیشود. برای بازیابی حاشیهنویسیهای یک نمونه، در عوض get_type_hints() را روی کلاس آن نمونه فراخوانی کنید (برای مثال، get_type_hints(type(obj))).
تغییر یافته در نسخهی 3.9: پارامتر include_extras بهعنوان بخشی از PEP 593 اضافه شد. برای اطلاعات بیشتر، مستندات مربوط به Annotated را ببینید.
تغییر یافته در نسخهی 3.11: پیشتر، اگر مقدار پیشفرض برابر با None تنظیم شده بود، Optional[t] به annotationهای تابع و متد افزوده میشد. اکنون annotation بدون تغییر بازگردانده میشود.
تغییر یافته در نسخهی 3.14: فراخوانی get_type_hints() روی نمونهها دیگر پشتیبانی نمیشود. برخی از نمونهها در نسخههای پیشین بهعنوان جزئیات پیادهسازی بدون مستند پذیرفته میشدند.
-
typing.get_origin(tp)¶
دریافت نسخهی بدون زیرنویس یک نوع: برای یک شیء typing به شکل X[Y, Z, ...]، X را برمیگرداند.
اگر X یک نام مستعار از ماژول typing برای یک کلاس توکار یا کلاسی از collections باشد، به کلاس اصلی نرمالسازی میشود. اگر X نمونهای از ParamSpecArgs یا ParamSpecKwargs باشد، ParamSpec زیربنایی را برمیگرداند. برای اشیای پشتیبانینشده، None را برمیگرداند.
مثالها:
assert get_origin(str) is None
assert get_origin(Dict[str, int]) is dict
assert get_origin(Union[int, str]) is Union
assert get_origin(Annotated[str, "metadata"]) is Annotated
P = ParamSpec('P')
assert get_origin(P.args) is P
assert get_origin(P.kwargs) is P
-
typing.get_args(tp)¶
آرگومانهای نوع را با تمام جایگزینیهای انجامشده دریافت میکند: برای یک شیء typing به فرم X[Y, Z, ...]، (Y, Z, ...) را برمیگرداند.
اگر X یک اجتماع (union) یا Literal باشد که در یک نوع عام دیگر قرار گرفته است، ممکن است ترتیب (Y, Z, ...) به دلیل نهانگاه نوع با ترتیب آرگومانهای اصلی [Y, Z, ...] متفاوت باشد. برای اشیای پشتیبانینشده، () را برمیگرداند.
مثالها:
assert get_args(int) == ()
assert get_args(Dict[int, str]) == (int, str)
assert get_args(Union[int, str]) == (int, str)
-
typing.get_protocol_members(tp)¶
مجموعهای از اعضای تعریفشده در یک Protocol را برمیگرداند.
>>> from typing import Protocol, get_protocol_members
>>> class P(Protocol):
... def a(self) -> str: ...
... b: int
>>> get_protocol_members(P) == frozenset({'a', 'b'})
True
برای آرگومانهایی که پروتکل نیستند، TypeError پرتاب میشود.
اضافه شده در نسخهی 3.13.
-
typing.is_protocol(tp)¶
تعیین میکند که آیا یک نوع، یک Protocol است یا خیر.
برای مثال:
class P(Protocol):
def a(self) -> str: ...
b: int
assert is_protocol(P)
assert not is_protocol(int)
این تابع فقط برای کلاسهای Protocol مقدار true را برمیگرداند، نه برای نامهای مستعار عام آنها:
class GenericP[T](Protocol):
def a(self) -> T: ...
b: int
assert not is_protocol(GenericP[int])
اضافه شده در نسخهی 3.13.
-
typing.is_typeddict(tp)¶
بررسی کنید که آیا یک نوع، TypedDict است.
برای مثال:
class Film(TypedDict):
title: str
year: int
assert is_typeddict(Film)
assert not is_typeddict(list | str)
# TypedDict is a factory for creating typed dicts,
# not a typed dict itself
assert not is_typeddict(TypedDict)
این تابع فقط برای کلاسهای TypedDict مقدار true را برمیگرداند، نه برای نامهای مستعار عام آنها:
class GenericFilm[T](TypedDict):
title: str
year: T
assert not is_typeddict(GenericFilm[int])
اضافه شده در نسخهی 3.10.
-
class typing.ForwardRef¶
کلاسی که برای بازنمایی داخلی تایپِ ارجاعهای پیشروی رشتهای استفاده میشود.
برای مثال، List["SomeClass"] بهطور ضمنی به List[ForwardRef("SomeClass")] تبدیل میشود. ForwardRef نباید توسط کاربر نمونهسازی شود، اما ممکن است توسط ابزارهای دروننگری استفاده شود.
نکته
انواع عام PEP 585 مانند list["SomeClass"] بهطور ضمنی به list[ForwardRef("SomeClass")] تبدیل نمیشوند و بنابراین بهطور خودکار به list[SomeClass] حل نمیشوند.
اضافه شده در نسخهی 3.7.4.
تغییر یافته در نسخهی 3.14: این اکنون نام مستعاری برای annotationlib.ForwardRef است. چندین رفتار مستندنشدهی این کلاس تغییر کرده است؛ برای مثال، پس از ارزیابی شدن یک ForwardRef، مقدار ارزیابیشده دیگر در نهانگاه ذخیره نمیشود.
-
typing.evaluate_forward_ref(forward_ref, *, owner=None, globals=None, locals=None, type_params=None, format=annotationlib.Format.VALUE)¶
ارزیابی یک annotationlib.ForwardRef بهعنوان یک type hint.
این کار مشابه فراخوانی annotationlib.ForwardRef.evaluate() است، اما برخلاف آن متد، evaluate_forward_ref() ارجاعهای پیشرو تودرتو درون راهنمای نوع را نیز بهصورت بازگشتی ارزیابی میکند.
برای آگاهی از معنای پارامترهای owner، globals، locals، type_params و format، مستندات annotationlib.ForwardRef.evaluate() را ببینید.
اضافه شده در نسخهی 3.14.
-
typing.NoDefault¶
یک شیء نشانگر (sentinel) که برای نشان دادن این به کار میرود که یک پارامتر نوع مقدار پیشفرض ندارد. برای مثال:
>>> T = TypeVar("T")
>>> T.__default__ is typing.NoDefault
True
>>> S = TypeVar("S", default=None)
>>> S.__default__ is None
True
اضافه شده در نسخهی 3.13.
-
typing.NoExtraItems¶
یک شیء sentinel که برای نشان دادن این استفاده میشود که یک TypedDict آرگومان کلاس extra_items را ندارد.
>>> from typing import TypedDict, NoExtraItems
>>> class Point(TypedDict):
... x: int
... y: int
...
>>> Point.__extra_items__ is NoExtraItems
True
ثابت¶
-
typing.TYPE_CHECKING¶
ثابت ویژهای که بررسیکنندههای نوع ایستا آن را True فرض میکنند. این ثابت در رانتایم False است.
ماژولی که ایمپورت آن پرهزینه است و فقط شامل انواع مورد استفاده برای حاشیهنویسیهای نوع است، میتواند بهصورت ایمن درون یک بلوک if TYPE_CHECKING: ایمپورت شود. این کار از ایمپورت واقعی ماژول در رانتایم جلوگیری میکند؛ حاشیهنویسیها بهصورت فوری ارزیابی نمیشوند (به PEP 649 مراجعه کنید)، بنابراین استفاده از نمادهای تعریفنشده در حاشیهنویسیها بیضرر است—تا زمانی که بعداً آنها را بررسی نکنید. ابزار تحلیل ایستای نوع شما در طول تحلیل ایستای نوع، TYPE_CHECKING را روی True تنظیم میکند، که به این معناست که ماژول ایمپورت خواهد شد و انواع در طول چنین تحلیلی بهدرستی بررسی خواهند شد.
استفاده:
if TYPE_CHECKING:
import expensive_mod
def fun(arg: expensive_mod.SomeType) -> None:
local_var: expensive_mod.AnotherType = other_fun()
اگر گاهی نیاز دارید حاشیهنویسیهای نوعی را که ممکن است حاوی نمادهای تعریفنشده باشند در رانتایم بررسی کنید، از annotationlib.get_annotations() با پارامتر format با مقدار annotationlib.Format.STRING یا annotationlib.Format.FORWARDREF استفاده کنید تا حاشیهنویسیها را بدون پرتاب NameError بهصورت امن بازیابی کنید.
اضافه شده در نسخهی 3.5.2.
نامهای مستعار منسوخ¶
این ماژول چندین نام مستعار منسوخ به کلاسهای از پیش موجود در کتابخانه استاندارد را تعریف میکند. این نامهای مستعار در ابتدا در ماژول typing گنجانده شده بودند تا از پارامتریزه کردن این کلاسهای عام با استفاده از [] پشتیبانی کنند. با این حال، این نامهای مستعار در پایتون 3.9 زائد شدند؛ هنگامی که کلاسهای از پیش موجود متناظر برای پشتیبانی از [] بهبود یافتند (به PEP 585 مراجعه کنید).
انواع زائد از پایتون 3.9 منسوخ شدهاند. هرچند ممکن است این نامهای مستعار در مقطعی حذف شوند، اما حذف آنها در حال حاضر برنامهریزی نشده است. بنابراین، در حال حاضر هیچ هشداری برای از رده خارج شدن این نامهای مستعار از سوی مفسر نشان داده نمیشود.
اگر در مقطعی تصمیم به حذف این نامهای مستعار منسوخ گرفته شود، مفسر حداقل در دو نسخهی پیش از حذف، هشدار از رده خارج شدن نشان خواهد داد. تضمین میشود که این نامهای مستعار در ماژول typing بدون هشدار از رده خارج شدن، حداقل تا پایتون 3.14 باقی بمانند.
بررسیکنندههای نوع تشویق میشوند که در صورتی که برنامهای که آن را بررسی میکنند حداقل نسخهی پایتون 3.9 یا جدیدتر را هدف قرار دهد، موارد استفاده از انواع منسوخ را نمادگذاری کنند.
نامهای مستعار برای انواع توکار¶
-
class typing.Dict(dict, MutableMapping[KT, VT])¶
نام مستعار منسوخشده برای dict.
توجه داشته باشید که برای حاشیهنویسی آرگومانها، ترجیح داده میشود از یک نوع مجموعه انتزاعی مانند Mapping استفاده شود، نه از dict یا typing.Dict.
-
class typing.List(list, MutableSequence[T])¶
نام مستعار منسوخشده برای list.
توجه داشته باشید که برای حاشیهنویسی آرگومانها، ترجیح داده میشود به جای استفاده از list یا typing.List از یک نوع مجموعه انتزاعی مانند Sequence یا Iterable استفاده شود.
-
class typing.Set(set, MutableSet[T])¶
نام مستعار منسوخشده برای builtins.set.
توجه کنید که برای حاشیهنویسی کردن آرگومانها، ترجیح داده میشود بهجای استفاده از set یا typing.Set، از یک نوع مجموعهی انتزاعی مانند collections.abc.Set استفاده شود.
-
class typing.FrozenSet(frozenset, AbstractSet[T_co])¶
نام مستعار منسوخ برای builtins.frozenset.
-
typing.Tuple¶
نام مستعار منسوخ برای tuple.
tuple و Tuple در سیستم نوع حالت خاصی دارند؛ برای جزئیات بیشتر، حاشیهنویسی تاپلها را ببینید.
-
class typing.Type(Generic[CT_co])¶
نام مستعار منسوخ برای type.
برای جزئیات درباره استفاده از type یا typing.Type در حاشیهنویسیهای نوع، نوع اشیای کلاس را ببینید.
اضافه شده در نسخهی 3.5.2.
نامهای مستعار برای نوعها در collections¶
-
class typing.DefaultDict(collections.defaultdict, MutableMapping[KT, VT])¶
نام مستعار منسوخشده برای collections.defaultdict.
اضافه شده در نسخهی 3.5.2.
-
class typing.OrderedDict(collections.OrderedDict, MutableMapping[KT, VT])¶
نام مستعار منسوخشده برای collections.OrderedDict.
اضافه شده در نسخهی 3.7.2.
-
class typing.ChainMap(collections.ChainMap, MutableMapping[KT, VT])¶
نام مستعار منسوخ برای collections.ChainMap.
اضافه شده در نسخهی 3.6.1.
-
class typing.Counter(collections.Counter, Dict[T, int])¶
نام مستعار منسوخشده برای collections.Counter.
اضافه شده در نسخهی 3.6.1.
-
class typing.Deque(deque, MutableSequence[T])¶
نام مستعار منسوخشده برای collections.deque.
اضافه شده در نسخهی 3.6.1.
نامهای مستعار برای سایر انواع مشخص¶
-
class typing.Pattern¶
-
class typing.Match¶
نامهای مستعار منسوخشده مربوط به انواع بازگشتی از re.compile() و re.search().
این انواع (و توابع متناظر) نسبت به AnyStr عام هستند. Pattern میتواند بهصورت Pattern[str] یا Pattern[bytes] تخصصی شود؛ Match میتواند بهصورت Match[str] یا Match[bytes] تخصصی شود.
-
class typing.Text¶
نام مستعار منسوخشده برای str.
Text برای فراهم کردن مسیری سازگار با آینده برای کد پایتون 2 ارائه شده است: در پایتون 2، Text نام مستعاری برای unicode است.
برای نشان دادن اینکه یک مقدار باید حاوی یک رشتهی یونیکد بهشکلی سازگار با هر دو Python 2 و Python 3 باشد، از Text استفاده کنید:
def add_unicode_checkmark(text: Text) -> Text:
return text + u' \u2713'
اضافه شده در نسخهی 3.5.2.
منسوخ شده از نسخهی 3.11: Python 2 دیگر پشتیبانی نمیشود، و بیشتر بررسیکنندههای نوع نیز دیگر از بررسی نوع کد Python 2 پشتیبانی نمیکنند. حذف این نام مستعار در حال حاضر برنامهریزی نشده است، اما به کاربران توصیه میشود بهجای Text از str استفاده کنند.
نامهای مستعار برای ABCهای ظرف در collections.abc¶
-
class typing.AbstractSet(Collection[T_co])¶
نام مستعار منسوخشده برای collections.abc.Set.
-
class typing.ByteString(Sequence[int])¶
نام مستعار منسوخ برای collections.abc.ByteString.
برای بررسی اینکه آیا obj پروتکل بافر را در رانتایم پیادهسازی میکند، از isinstance(obj, collections.abc.Buffer) استفاده کنید. برای استفاده در حاشیهنویسیهای نوع، یا از Buffer استفاده کنید یا از یک اجتماع (union) که بهصراحت نوعهایی را که کد شما از آنها پشتیبانی میکند مشخص میکند (مثلاً bytes | bytearray | memoryview).
ByteString در ابتدا قرار بود یک کلاس انتزاعی باشد که بهعنوان ابرنوع هر دو bytes و bytearray عمل کند. با این حال، از آنجا که این ABC هرگز هیچ متدی نداشت، دانستن اینکه یک شیء نمونهای از ByteString است، هرگز در عمل اطلاعات مفیدی درباره آن شیء به شما نمیداد. سایر انواع رایج بافر مانند memoryview نیز هرگز بهعنوان زیرنوعهایی از ByteString شناخته نمیشدند (چه در رانتایم و چه از سوی بررسیکنندههای نوع ایستا).
برای جزئیات بیشتر، PEP 688 را ببینید.
منسوخ شده از نسخهی 3.9, در نسخهی 3.17 حذف خواهد شد.
-
class typing.Collection(Sized, Iterable[T_co], Container[T_co])¶
نام مستعار منسوخشده برای collections.abc.Collection.
-
class typing.Container(Generic[T_co])¶
نام مستعار منسوخ برای collections.abc.Container.
-
class typing.ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]])¶
نام مستعار منسوخ برای collections.abc.ItemsView.
-
class typing.KeysView(MappingView, AbstractSet[KT_co])¶
نام مستعار منسوخ برای collections.abc.KeysView.
-
class typing.Mapping(Collection[KT], Generic[KT, VT_co])¶
نام مستعار منسوخ برای collections.abc.Mapping.
-
class typing.MappingView(Sized)¶
نام مستعار منسوخ برای collections.abc.MappingView.
-
class typing.MutableMapping(Mapping[KT, VT])¶
نام مستعار منسوخشده برای collections.abc.MutableMapping.
-
class typing.MutableSequence(Sequence[T])¶
نام مستعار منسوخشده برای collections.abc.MutableSequence.
-
class typing.MutableSet(AbstractSet[T])¶
نام مستعار منسوخشده برای collections.abc.MutableSet.
-
class typing.Sequence(Reversible[T_co], Collection[T_co])¶
نام مستعار منسوخشده برای collections.abc.Sequence.
-
class typing.ValuesView(MappingView, Collection[_VT_co])¶
نام مستعار منسوخ برای collections.abc.ValuesView.
نامهای مستعار برای کلاسهای پایه انتزاعی (ABC) در contextlib¶
-
class typing.ContextManager(Generic[T_co, ExitT_co])¶
نام مستعار منسوخشده برای contextlib.AbstractContextManager.
نخستین پارامتر نوع، T_co، نشاندهندهی نوع برگرداندهشده توسط متد __enter__() است. دومین پارامتر نوع اختیاری، ExitT_co، که بهطور پیشفرض bool | None است، نشاندهندهی نوع برگرداندهشده توسط متد __exit__() است.
اضافه شده در نسخهی 3.5.4.
تغییر یافته در نسخهی 3.13: دومین پارامتر نوع اختیاری، ExitT_co، افزوده شد.
-
class typing.AsyncContextManager(Generic[T_co, AExitT_co])¶
نام مستعار منسوخشده برای contextlib.AbstractAsyncContextManager.
نخستین پارامتر نوع، T_co، نوعی را نشان میدهد که توسط متد __aenter__() بازگردانده میشود. دومین پارامتر نوع اختیاری، AExitT_co، که پیشفرض آن bool | None است، نوعی را نشان میدهد که توسط متد __aexit__() بازگردانده میشود.
اضافه شده در نسخهی 3.6.2.
تغییر یافته در نسخهی 3.13: پارامتر نوع اختیاری دوم، AExitT_co، افزوده شد.
خط زمانی از رده خارج شدن ویژگیهای اصلی¶
برخی از قابلیتهای typing منسوخ شدهاند و ممکن است در نسخهای آینده از پایتون حذف شوند. جدول زیر برای راحتی شما، مهمترین موارد منسوخ را خلاصه میکند. این موضوع ممکن است تغییر کند و همهی موارد منسوخ فهرست نشدهاند.
© حق نشر 2001 Python Software Foundation.
این صفحه تحت مجوز بنیاد نرمافزار پایتون نسخه ۲ منتشر شده است.
مثالها، دستورالعملها، و سایر کدهای موجود در مستندات همچنین تحت مجوز بدون بند BSD منتشر شدهاند.
برای اطلاعات بیشتر به تاریخچه و مجوز مراجعه کنید.
بنیاد نرمافزار پایتون یک شرکت غیرانتفاعی است.
لطفاً کمک مالی کنید.
آخرین بهروزرسانی در نوامبر 12, 2026 (06:19 UTC).
آیا اشکالی یافتید؟
ساخته شده با Sphinx 9.1.0.
|