2021年8月13日 星期五

[ Python 常見問題 ] How should a python type hint require that a value has a given attribute?

 Source From Here

Question
Let's say I have a simple function like this:
  1. def handle(d: People) -> None:  
  2.   print(f"{d.name}/{d.age}")  
I would like type hinting People to check if the given object has attributes "name" (str) and "age" (int).

HowTo
This is exactly what Protocols are for. In short, Protocols let you use structural instead of nominal subtyping. With nominal subtyping, type A is a subtype of B if A explicitly inherits or extends B. With structural subtyping, type A is a subtype of B if it has the same method and attribute "signatures" as B (with some restrictions).

For example:
  1. from typing import Protocol  
  2.   
  3.   
  4. class People(Protocol):  
  5.   name: str  
  6.   age: int  
  7.   
  8.   
  9. class P1:  
  10.   def __init__(self) -> None:  
  11.     self.name = 'John'  
  12.     self.age = 1  
  13.   
  14.   
  15. class P2:  
  16.   def __init__(self) -> None:  
  17.     self.name = 'Ken'  
  18.     self.age = 56  
  19.     self.extra_attr = 'test'  
  20.   
  21.   
  22. class P3:  
  23.   def __init__(self) -> None:  
  24.     self.name = 'Mary'  
  25.   
  26.   
  27. class P4:  
  28.   def __init__(self) -> None:  
  29.     self.age = 99  
  30.   
  31.   
  32. def handle(d: People) -> None:  
  33.   print(f"{d.name}/{d.age}")  
  34.   
  35. handle(P1())  
  36. handle(P2())  
  37. "P3" is missing following "People" protocol member: age  
  38. handle(P3())  
  39. "P4" is missing following "Device" protocol member: name  
  40. handle(P4())  
You can leverage mypy to do the typing check:
# mypy test.py
test.py:40: error: Argument 1 to "handle" has incompatible type "P3"; expected "People"
test.py:40: note: "P3" is missing following "People" protocol member:
test.py:40: note: age

test.py:42: error: Argument 1 to "handle" has incompatible type "P4"; expected "People"
test.py:42: note: "P4" is missing following "People" protocol member:
test.py:42: note: name
Found 2 errors in 1 file (checked 1 source file)

You can also find slightly more complex examples of using Protocols in typeshed, the repository of type hints for the Python standard library.

Though, I suppose this all matters only if you actually intend on using static analysis in your code. If not, you could maybe do something simpler and just define a custom type alias to Any, document what that alias is "supposed" to mean, and use that alias instead of a full-fledged protocol. That alias would be almost completely useless for the purposes of static analysis/autocompletion tools/etc, but humans generally have no issues reading comments.

Supplement
Is there a way to make flake8 check for type hints in the source

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...