2021年7月31日 星期六

[ Python 常見問題 ] Python type-hinting, indexable object

 Source From Here

Question
My function needs to accept an object, from which data can be extracted by index, viz. a List or an instance with defined __getitem__ method.

Which type can I use for type hinting this argument?

HowTo
There are several different ways you can do this.

If you're ok with using only custom classes (that you can write) as indexable containers:
  1. from typing import TypeVar, Generic  
  2.   
  3. ReturnType = TypeVar('ReturnType')  
  4.   
  5. class IndexableContainer(Generic[ReturnType]):  
  6.   def __getitem__(self, key: int) -> ReturnType:  
  7.     ...  
  8.   
  9.   
  10. def get_last_element(container: IndexableContainer[int]) -> int:  
  11.   return container[-1]  
  12.   
  13.   
  14. my_container = [1,2,3]  
  15. print(get_last_element(my_container))  
Output:
3

The issue is, of course, that if you wanted to pass in a plain old list into the function, you wouldn't be able to do so since list doesn't subclass your custom type.

We could maybe special-case certain inputs via clever use of the @overload decorator and unions, but there's a second, albeit experimental, way of doing this known as Protocols.

Protocols basically let you express "duck typing" in a sane way using type hints: the basic idea is that we can tweak IndexableContainer to become a protocol. Now, any object that implements the __getitem__ method with the appropriate signature is counted as a valid IndexableContainer, whether or not they subclass that type or not.

The only caveat is that Protocols are currently experimental and (afaik) only supported by mypy. The plan is to eventually add protocols to the general Python ecosystem -- see PEP 544 for the specific proposal -- but I haven't kept track of the discussion/don't know what the status of that is.

In any case, to use protocols, install the typing_extensions module using pip. Then, you can do the following:
  1. from typing import TypeVar, Generic  
  2. from typing_extensions import Protocol  
  3.   
  4. ReturnType = TypeVar('ReturnType')  
  5.   
  6. class IndexableContainer(Protocol, Generic[ReturnType]):  
  7.   def __getitem__(self, key: int) -> ReturnType:  
  8.     ...  
  9.   
  10.   
  11. def get_last_element(container: IndexableContainer[int]) -> int:  
  12.   return container[-1]  
  13.   
  14.   
  15. my_container = [1,2,3]  
  16. print(get_last_element(my_container))  
The last ane easier one is to use typing Sequence:
  1. from typing import TypeVar, Sequence  
  2.   
  3. EType = TypeVar('ElementType'int, str)  
  4.   
  5.   
  6. def get_last_element(container: Sequence[EType]) -> EType:  
  7.   return container[-1]  
  8.   
  9.   
  10. my_int_container = [1,2,3]  
  11. my_str_container = ["a""b""c"]  
  12. print(get_last_element(my_int_container))  
  13. print(get_last_element(my_str_container))  
Ouptut
3
c


1 則留言:

  1. MicroTouch Titanium trim on display with detachable lid
    The MicroTouch Titanium dewalt titanium drill bit set trim allows the user to experience titanium gravel bike all the titanium bracelet essential components of titanium mountain bikes this iconic titanium nipple barbells device. These included the main

    回覆刪除

[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...