Proposal: Add coerced type narrowing similar to 'cast'
還沒有人認領這個 Issue。
評估
研究方向
該 issue 未列出任何檔案、測試或實作入口。首先檢視提議的 type_assert 和 ensure_type 形式,以及與 Intersection 和 Not 相關的討論;在實作之前定義支援的語意、執行期行為和驗收測試。
由索引模型根據 Issue 內容生成。
描述
My suggestion is to add a way to coerce type narrowing without any runtime change,
by adding new type_assert and/or ensure_type.
def function(arg: Any):
type_assert isinstance(arg, int)
reveal_type(arg) # Revealed type: "builtins.int"
def function(arg: Any):
ensure_type(arg, int)
reveal_type(arg) # Revealed type: "builtins.int"
These functions do nothing at runtime! they only help with the types.
Why not cast(int, arg)?
-
castcompletely replaces the type and we need to write a full new type.
With type narrowing it's only necessary to limit the options of the existing type.def function(arg: Union[int, str, list]): arg = cast(Union[str, list], arg) reveal_type(arg) # Revealed type: "str | list"def function(arg: Union[int, str, list]): type_assert not isinstance(arg, int) # only need to remove 'int' reveal_type(arg) # Revealed type: "str | list" -
castis more dangerous because we ignore the previous type. with narrowing we just limit the options of the previous type.def function(arg: Union[int, str, list]): arg1 = cast(dict, arg) reveal_type(arg1) # Revealed type: "dict"def function(arg: Union[int, str, list]): type_assert not isinstance(arg, dict) # Error: Subclass of "int" and "dict[Any, Any]" cannot existdef function(arg: Union[int, str, list]): type_assert not isinstance(arg, int) type_assert not isinstance(arg, str) type_assert not isinstance(arg, list) reveal_type(arg) # Error: Statement is unreachable -
castcan't doIntersection(yet). explained below.
Why type_assert and not a normal assert?
assertmakes it slower at runtime, and sometimes we careassertcan break things when improving types of an old code base
The downsides:
- Without
assertor if-else conditions at runtime, the coerced narrowing ignores the real type and is dangerous, almost likecast.
With Intersection type
Until we have Intersection type, this kind of things are problematic:
class Animal:
def say_my_name(self) -> None:
print("My name is Animal")
@runtime_checkable
class CanFlyProtocol(Protocol):
def fly(self) -> None: ...
class Bird(Animal, CanFlyProtocol):
def fly(self) -> None:
print("Fly")
def let_it_fly(animal: Animal): # we can't restrict the argument type to be Animal AND CanFlyProtocol
animal.say_my_name()
animal.fly() # Error: "Animal" has no attribute "fly"
Even cast can't help us, but we can narrow the type!
def let_it_fly(animal: Animal):
assert isinstance(animal, CanFlyProtocol)
animal.say_my_name()
animal.fly()
reveal_type(animal) # Revealed type: "<subclass of "Animal" and "CanFlyProtocol">"
Type checkers can understand Intersection when we narrow the type, great!
But what if we don't want to change runtime behavior? for this we can
replace assert with the suggested type_assert or ensure_type!
def let_it_fly(animal: Animal):
type_assert isinstance(animal, CanFlyProtocol)
animal.say_my_name()
animal.fly()
reveal_type(animal) # Revealed type: "<subclass of "Animal" and "CanFlyProtocol">"
A side note: with
type_assertwe probably can stop adding@runtime_checkableto Protocols, if we only added it for this kind of type-hint only issues thatassert isinstance(animal, CanFlyProtocol)solved.
Performingisinstancewith Protocol is very slow so this benefit is not small.
ensure_type with Not
See:
def function(arg: Union[int, str, list]):
type_assert not isinstance(arg, int)
reveal_type(arg) # Revealed type: "str | list"
How to do not isinstance with ensure_type? we have two options:
-
Add a similar
ensure_not_typedef function(arg: Union[int, str, list]): ensure_not_type(arg, int) reveal_type(arg) # Revealed type: "str | list" -
Wait for the
Not[]typedef function(arg: Union[int, str, list]): ensure_type(arg, Not[int]) reveal_type(arg) # Revealed type: "str | list"
- 主要語言
- Python
- 星號
- 1.8k
- 分支
- 302
- 平均合併
- 4 小時 38 分鐘
- 30 天內合併 PR
- 6
環境準備
這個專案沒有提供開發容器、Dockerfile 或貢獻指南,環境需要你自己搭建:先看它的 README,通用步驟見我們的新手貢獻指南。
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
python/typing 的其他 Issue
-
topic: typing spec
難度 2/5 1-3 小時 新手友好度 72/100
-
topic: typing spec
難度 2/5 1-3 小時 新手友好度 75/100
-
Update reference/generics.html with PEP695 type parameter syntax可能已有人在做 @BHUVANSH855 於 181 天前認領。 未關閉topic: documentation
難度 2/5 1-3 小時 新手友好度 76/100
-
topic: documentation
難度 2/5 1-3 小時 新手友好度 65/100
-
Finals and Literals: Spec contradiction可能已有人在做 @srittau 於 35 天前認領。 未關閉topic: conformance tests topic: typing spec
難度 3/5 1-2 天 新手友好度 72/100
相似的 Issue
-
難度 2/5 1-3 小時 新手友好度 82/100
LearningCircuit/local-deep-research#7206 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 68/100
chingu-voyages/V62-tier3-team-33#285 ·
維護者通常 1 天內回覆
-
Proxy drops log notifications from backends that don't send FastMCP's msg/extra dict可能已有人在做 @asasemahmed 今天認領。 未關閉bug server
難度 2/5 1-3 小時 新手友好度 78/100
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 82/100
維護者通常 1 天內回覆
-
[Bug]: Bedrock request metadata forwarding does not work for /embeddings可能已有人在做 關聯的 PR 仍在進行中或已合併。 未關閉bug llm translation
難度 2/5 1-3 小時 新手友好度 78/100
維護者通常 1 天內回覆