2021年8月28日 星期六

[ Python 常見問題 ] What's the best way to split a string into fixed length chunks

 Source From Here

Question
As title, I want a function as below:
  1. def split_text_into_n_chuck(text, n=2):  
  2.   pass  
So I can use it this way:
>>> text = 'abcdefghijk'
>>> split_text_into_n_chuck(text)
['ab', 'cd', 'ef', 'gh', 'ij', 'k']

HowTo
A simple implementation as below:
  1. def split_text_into_n_chuck(text, n=2):    
  2.     return [text[i:i+n] for i in range(0, len(text), n)]  
For example:
>>> split_text_into_n_chuck(text, n=3)
['abc', 'def', 'ghi', 'jk']


[ Python 常見問題 ] Type hints with user defined classes

 Source From Here

Question
Couldn't seem to find a definitive answer. I want to do a type hint for a function and the type being some custom class that I have defined, called it CustomClass. And then let's say in some function, call it FuncA(arg), I have one argument named arg. Would the correct way to type hint FuncA be:
  1. def FuncA(arg: CustomClass):  
Or would it be:
  1. def FuncA(Arg:Type[CustomClass]):  
HowTo
The former is correct, if arg accepts an instance of CustomClass:
  1. def FuncA(arg: CustomClass):  
  2.     #     ^ instance of CustomClass  
In case you want the class CustomClass itself (or a subtype), then you should write:
  1. from typing import Type  # you have to import Type  
  2.   
  3. def FuncA(arg: Type[CustomClass]):  
  4.     #     ^ CustomClass (class object) itself  
Like it is written in the documentation about Typing:
  1. class typing.Type(Generic[CT_co])  
A variable annotated with may accept a value of type C. In contrast, a variable annotated with Type[C] may accept values that are classes themselves - specifically, it will accept the class object of C.

The documentation includes an example with the int class:
  1. a = 3         # Has type 'int'  
  2. b = int       # Has type 'Type[int]'  
  3. c = type(a)   # Also has type 'Type[int]'  


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

2021年8月1日 星期日

[ Python 常見問題 ] How do I type hint a method with the type of the enclosing class?

 Source From Here

Question
I have the following code in python 3:
  1. class Position:  
  2.   
  3.     def __init__(self, x: int, y: int):  
  4.         self.x = x  
  5.         self.y = y  
  6.   
  7.     def __add__(self, other: Position) -> Position:  
  8.         return Position(self.x + other.x, self.y + other.y)  
But the return type hinting def __add__(self, other: Position) -> Position will fail.

HowTo
If you are using Python 3.10 or later, it just works. As of today (2019), in 3.7+ you must turn this feature on using a future statement (from __future__ import annotations). In Python 3.6 or below, use a string.

I guess you got this exception:
  1. NameError: name 'Position' is not defined  
This is because Position must be defined before you can use it in an annotation unless you are using Python 3.10 or later.

Python 3.7+: from __future__ import annotations
Python 3.7 introduces PEP 563: postponed evaluation of annotations. A module that uses the future statement from __future__ import annotations will store annotations as strings automatically:
  1. from __future__ import annotations  
  2.   
  3. class Position:  
  4.     def __add__(self, other: Position) -> Position:  
  5.         ...  
This is scheduled to become the default in Python 3.10. Since Python still is a dynamically typed language so no type checking is done at runtime, typing annotations should have no performance impact, right? Wrong! Before python 3.7 the typing module used to be one of the slowest python modules in core so if you import typing you will see up to 7 times increase in performance when you upgrade to 3.7.

Python <3.7: use a string
According to PEP 484, you should use a string instead of the class itself:
  1. class Position:  
  2.     ...  
  3.     def __add__(self, other: 'Position') -> 'Position':  
  4.        ...  

[ Python 常見問題 ] When using unittest.mock.patch, why is autospec not True by default?

  Source From  Here Question When you patch a function using  mock , you have the option to specify  autospec  as True: If you set  autospec...