-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
110 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Introduction | ||
|
||
Python的各种设计模式 | ||
- 用linting辅助检测具体设计 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# annotations | ||
|
||
|
||
from typing import List, Sequence, Protocol | ||
|
||
|
||
class IA: pass | ||
class IB(IA): pass | ||
|
||
class P(Protocol): | ||
def h(self) -> List[IA]: ... | ||
|
||
|
||
class A: | ||
def f(self) -> List[IA]: | ||
return [IA()] | ||
|
||
def g(self) -> Sequence[IA]: | ||
return [IA()] | ||
|
||
def h(self) -> List[IA]: | ||
return [IA()] | ||
|
||
|
||
class B(A): | ||
def f(self) -> List[IB]: | ||
# NOTE: it is a invalid override in linting. | ||
return [IB()] | ||
|
||
def g(self) -> Sequence[IB]: | ||
# NOTE: it is a valid overriding | ||
return [IB()] | ||
|
||
def h(self) -> List[IB]: | ||
# NOTE: it is a invalid override in linting. | ||
# So protocal does not help here | ||
return [IB()] | ||
|
||
|
||
# generic | ||
|
||
from typing import Generic, TypeVar, List | ||
# Define a type variable | ||
T = TypeVar('T') | ||
class Stack(Generic[T]): | ||
def __init__(self): | ||
self._items: List[T] = [] | ||
def push(self, item: T) -> None: | ||
self._items.append(item) | ||
def pop(self) -> T: | ||
return self._items.pop() | ||
def is_empty(self) -> bool: | ||
return len(self._items) == 0 | ||
# Usage | ||
int_stack = Stack[int]() | ||
int_stack.push(1) | ||
int_stack.push(2.) # NOTE: it is runnable but does not confirm with linting rules. | ||
print(int_stack.pop()) # Output: 2.0 | ||
print(int_stack.pop()) # Output: 1 | ||
|
||
int_stack = Stack() | ||
int_stack.push(1) | ||
int_stack.push(2.) | ||
print(int_stack.pop()) # Output: 2.0 | ||
print(int_stack.pop()) # Output: 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
""" | ||
# We'll check the design with `ruff check` & `mypy` | ||
""" | ||
from typing import Generic, TypeVar | ||
|
||
ASpecificBaseTask = TypeVar("ASpecificBaseTask", bound="BaseTask") | ||
# Define a type, that refer to a more specific subclass than general `BaseTask` | ||
|
||
|
||
# Core Framework | ||
class BaseTask: | ||
... | ||
|
||
|
||
class BaseSolver(Generic[ASpecificBaseTask]): | ||
""" | ||
From a semantic perspective, | ||
It defines a framework. But it is not designed to handle general BaseTask. | ||
Instead, it is designed to handle a specific subclass of BaseTask (But all kinds of specific subclasses can be handled in this class). | ||
""" | ||
|
||
def g(self, a: ASpecificBaseTask) -> ASpecificBaseTask: | ||
return a | ||
|
||
|
||
# concrete framework | ||
class MTask(BaseTask): | ||
... | ||
|
||
|
||
class MSolver(BaseSolver[MTask]): | ||
|
||
def g(self, a: MTask) -> MTask: | ||
"""`MSolver.g` only works when a is MTask""" | ||
return a | ||
|
||
|
||
ms = MSolver() | ||
print(isinstance(ms, BaseSolver)) # it will not affect the type checking |