or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing
xxxxxxxxxx
fin-pyコードリーディング会#4
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →概要
fin-pyについて
https://github.com/fin-py/guideline
次回のイベント
TBD
Slack
https://docs.google.com/forms/d/e/1FAIpQLSd9oVlrCMHEuD3PN0x3QcMgeQGy6Sj90d6uP1CQXQnArX9YqQ/viewform
参加方法
fin-pyコードリーディング会#4
終了
重要
Zoomに参加したら、出欠確認にチェックを入れてください
前回の様子
タイムテーブル
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →コードリーディング
読むコード
store.py
発表者のかたは、コードを読んだ際のメモ書きなどを下記に記載してください
ほかの形式でまとめたかたは要点(もし可能であれば資料のリンク)を記載してください
参考情報
自己紹介・コメント・メモ
どりらん
しんせいたろう
やろころ
AAACC
まちゅけん
もりもと
発表者
もりもと
DataStore
抽象基底クラス
DataStore を直接インスタンス化して使うことを意図していないなら abc を使って抽象基底クラスにすると、利用者に継承して使うものであることを設計者の意図として伝えられる。
抽象基底クラスは、設計者の意図を伝えられるというメリットだけでなく、例えば
@abstractmethod
でサブクラスのモデルそれぞれで実装が必要なメソッドを明示して、未実装の場合は、インスタンス化したときにエラーにしたりできる。テストとも相性がよいはず。動作確認。
未使用のクラス変数
クラス変数の
_KEYS
からインスタンス変数を初期化するのはあまり意義があるようにはみえないかな。明示的に__init__
で keys を渡すか、_init
で渡すようなやり方の方がいいのでは?self._KEYS
を直接参照しているコードもなさそうだし。iter のラッピング
iter
いるのかな?と思ったけど、これは型チェックのために必要なのかな?KeyError のロギング
一般論として例外を無視するコードはよくない。
どうしても仕方ないときは logging.debug などを使って、通常 (infoレベル) はログ出力しないけど、調査したいときに切り替えられるようにしておくとまだよいとは思う。
wait 処理
wait を呼び出したときに
await event.wait()
でコルーチンが切り替わっているときに ret が変更されることを期待しているコードにみえる。イベントの登録と値の取得は queue のようなものでやった方が保守しやすいコードになるような気がする。少なくともこのコードだけ読んだら ret は空リストが返るようにしか読めない。
DataStoreManager
これも一般論として
Manager
という名前は役割が曖昧になるのであまり使われない名前になりつつある気がしている。このクラスは DataStore と asyncio.Event の扱いがセットになっていてその役割の曖昧さがManager
という名前に現れている気がする。DataStore からみたらコレクションにみえるし、Event からみたらイベントハンドラーにみえる。リファクタリングするなら2つに分割して、それぞれの責務に限定した方が保守はしやすくなる気がする。iscoroutinefunction
これはどこで使っている?
DataStore 要素の取得
この処理は同じにみえるので Pythonic な概念だと、どちらかのやり方に統一した方がよいのではないか?
動作確認。
どりらん
list[str]
のように書けるfrom __future__ import annotations
でジェネリクスが使えるEllipsis
...
と書けるnumpyの例
...
で省略できる_insert
_update
_delete
_sweep_with_key
_sweep_without_key
get
pop
keyitem
はコンストラクタに入れてインスタンス属性にはできない?_sweep_with_key
と_sweep_without_key
は同様な処理なので、1つのメソッドにまとめられそう_pop
で、処理もpopに近いので、del
よりはpop
をにしたほうがわかりやすそうtyping.TypeVar
bound
でDataStore
クラスが親クラスであることを指定DataStoreManager
models
の親クラス__getitem__
と__contains__
が実装されているので、コンテナ型として扱える参考情報
しんせいたろう
動作確認
スクリプト
出力
読みたいところ:
[[best price, size], [next best price, size]... ]
{'market': 'FTT-PERP', 'side': 'buy', 'price': 53.2035, 'size': 14.3}
)に変換しているところを読む読む
hdlr_json=store.onmessage
して、ウェブソケットデータを受信したら、onmessage関数で処理するように設定してあるのでpybotters.FTXDataStore()
を読むmodels/ftx.py
15行目FTXDataStore()
をインスタンス化する時に、create
メソッドを使って、チャネル名ごとにdatastore_class
を指定datastore_class
はOrderBook
createメソッド:
store.py
208行目self._stores
に、データストアオブジェクトを格納OrderBook データストアクラス:
models/ftx.py
117行目{'market': 'FTT-PERP', 'side': 'buy', 'price': 53.2035, 'size': 14.3}
に変換されている。sorted
関数は使われてないっぽい)self._update()
:store.py
67行目self._keys
はOrderBook
で定義されている_KEYS = ['market', 'side', 'price']
{'market': 'FTT-PERP', 'side': 'buy', 'price': 52.9075}
という形のデータから keyhash を作成self._data
に、keyhash と 板情報のデータを追加self._data
は__iter__
で return されているので、ユーザはstore.orderbook
でアクセス可store.orderbook.find({"side": "buy"}
:store.py
153行目__iter__
で取得できるデータ。つまりself._data.values()
{'side': 'buy'}
)にマッチしたデータだけフィルタして返すまとめ:
DataStore
とDataStoreManager
を継承しながら定義してある。(models
配下)やろころ
UUIDとは
class DataStore:
def init(self, keys: List[str] = [], data: List[Item] = []) -> None: 各種インスタンス変数の初期化
def len(self) -> int: データの長さを返却
def len(self) -> int: データのイテレータを返却
@staticmethod
def _hash(item: Dict[str, Hashable]) -> int: itemのハッシュ値を返却
def _insert(self, data: List[Item]) -> None: dataへのデータ挿入
def _update(self, data: List[Item]) -> None: dataへの要素更新
def _delete(self, data: List[Item]) -> None: dataの要素削除
def _clear(self) -> None: data等の削除
def _sweep_with_key(self) -> None: dataがMAXLENより大きいときのkeyによるsweep処理?(_insert()や_update()で利用)
def _sweep_without_key(self) -> None: dataがMAXLENより大きいときのkeyによらないsweep処理?
def get(self, item: Item) -> Optional[Item]:
def _pop(self, item: Item) -> Optional[Item]:
def find(self, query: Item = {}) -> List[Item]:
def _find_and_delete(self, query: Item = {}) -> List[Item]:
def _set(self, data: List[Item] = None) -> None:
async def wait(self) -> List[Item]:
TDataStore = TypeVar('TDataStore', bound=DataStore)
class DataStoreManager:
def init(self) -> None:
def getitem(self, name: str) -> Optional['DataStore']:
def contains(self, name: str) -> bool:
def create( 中略 ) -> None:
def get(self, name: str, type: Type[TDataStore]) -> TDataStore:
def _onmessage(self, msg: Any, ws: ClientWebSocketResponse) -> None:
def onmessage(self, msg: Any, ws: ClientWebSocketResponse) -> None:
def _set(self) -> None:
async def wait(self) -> None:
発表者5
出席確認
次回
__init__.py
auth.py
client.py
request.py
store.py
typedefs.py
ws.py
tests
docs
(ドキュメント関連)pyproject.toml
(パッケージ関連)pytest.yml
(CI, GitHub Actions)auth.py
を読む