Closed d-makarov-d closed 2 months ago
Benchmarks for coss identification of data, that is processed
NPoints | Method | Init time | init mem | time | mem |
---|---|---|---|---|---|
1000 | simple | 1.1842000276374165e-06 s | 520 B | 0.27270523269999103 s | 1591 B |
5000 | simple | 9.747000149218366e-07 s | 696 B | 1.362887727999987 s | 1307 B |
10000 | simple | 9.039000360644422e-07 s | 696 B | 2.6923894366999774 s | 1136 B |
20000 | simple | 9.348000276077073e-07 s | 696 B | 5.2818602004999775 s | 908 B |
50000 | simple | 8.591000550950412e-07 s | 696 B | 13.299184179299937 s | 794 B |
100000 | simple | 8.72999953571707e-07 s | 696 B | 27.283664147299987 s | 851 B |
1000 | KDTree | 0.1397985143000028 s | 2496 B | 0.009556023200002529 s | 648 B |
5000 | KDTree | 0.6949047902999951 s | 1464 B | 0.04530520970000111 s | 568 B |
10000 | KDTree | 1.3894745881999995 s | 1464 B | 0.09047014139999873 s | 568 B |
20000 | KDTree | 2.7816018049999967 s | 1464 B | 0.18125534010000025 s | 4016 B |
50000 | KDTree | 6.960445219999997 s | 1464 B | 0.4546720884000024 s | 568 B |
100000 | KDTree | 13.979613529100003 s | 1464 B | 0.9161960672000078 s | 568 B |
1000 | PG | 0.19790853849997347 s | 138917 B | 0.005958995499997855 s | 127815 B |
5000 | PG | 0.8417563099999938 s | 121011 B | 0.007068349300004684 s | 117354 B |
10000 | PG | 1.6844553614999995 s | 118249 B | 0.008423732200003541 s | 119797 B |
20000 | PG | 3.3574917550000123 s | 118118 B | 0.011614575800001603 s | 128431 B |
50000 | PG | 8.103130566499999 s | 117811 B | 0.02065682040000638 s | 136188 B |
100000 | PG | 16.223209063500008 s | 116437 B | 0.036517746699996675 s | 151651 B |
По возвращаемым эксепшенам - это в отдельную ищью, либо к рефакторингу добавить. Потому что это у меня тянется много откуда, соответственно кучу кода надо менять
По возвращаемым эксепшенам - это в отдельную ищью, либо к рефакторингу добавить. Потому что это у меня тянется много откуда, соответственно кучу кода надо менять
Ну я не имею ввиду сразу везде менять, но по крайней мере в коде, который меняется в этом ПРе, можно сразу поменять, сам же себе потом работу облегчишь:
Вот эти функции например и создаются, и используются только в новом коде, тут сразу же можно сделать правильное возвращающее значение
Вот это возвращаемое значение тоже используется только в новом коде, можно сразу сделать правильно
Ну в целом то надо во всем коде поменять) Потому что если сейчас быстро могу только |
на dataclass
поменять, но от этого эксепшены не перестанут возвращаться
Ну в целом то надо во всем коде поменять) Потому что если сейчас быстро могу только Optional на dataclass поменять, но от этого эксепшены не перестанут возвращаться
Ну сейчас у тебя как будто не много надо сделать
res.error is None
вместо isinstance
Да и вроде всё, всё остальное без этого сработает, всё остальное можно поменять уже отдельно
Вообще мне Union
больше нравится чем dataclass
. Он однозначней, либо то, либо другое. А в такой Result
формально можно например два None
запихнуть
Или это некая стандартная практика для питона? Таким образом результат оформлять?
Или это некая стандартная практика для питона? Таким образом результат оформлять?
Ну смотри, ответ на две части разобью
Стандартная практика для питона - рейзить ошибки, а не возвращать (как и для кучи других языков, включая джаву и котлин, кажется).
Тогда код можно переписать в виде
async def invoke(
self,
param: CrossIdentificationParam,
simultaneous_data_provider: CrossIdSimultaneousDataProvider,
user_param: CrossIdentificationUserParam,
) -> result.CrossIdentifySuccess:
if param.names is None and param.coordinates is None:
raise result.CrossIdentificationEmptyException()
....
return res
и получится норм с точки зрения практики питона.
Следующее утверждение, уже связанное не конкретно с питоном, а в целом с использованием функции - бросание ошибок, как выше, усложняет читаемость функции, потому что по сигнатуре функции def invoke(self, CrossIdentificationParam, CrossIdSimultaneousDataProvider, CrossIdentificationUserParam) -> result.CrossIdentifySuccess
непонятно, какие ошибки она бросает, и соответственно чтобы пользователь функции мог понять, как ей пользоваться, ему нужно залезать в реализацию функции и просмотреть код функции на предмет возможных ошибок. Это часто ведёт к ошибкам из-за человеческого фактора - читатель может не увидеть один из возможных видов ошибок, или, например, при изменении логики добавим новый вид ошибок и забудем поменять во всех местах пользования.
Поэтому мне тут кажется более правильным возвращать структуру, которая в себе хранит ошибку, которая может быть None. Это не обязательно может быть dataclass
, можно сделать, например, tuple:
async def invoke(
self,
param: CrossIdentificationParam,
simultaneous_data_provider: CrossIdSimultaneousDataProvider,
user_param: CrossIdentificationUserParam,
) -> tuple[result.CrossIdentifySuccess | None, CrossIdentificationError | None]:
if param.names is None and param.coordinates is None:
return None, CrossIdentificationEmptyError
....
return res, None
И тогда в месте использования будет что-то типа
result, err = CrossIdentifyUseCase().invoke(.....)
if err is not None:
'возвращаем ошибку'
'работаем с результатом'
Если не нравится, что они могут оба быть None, можешь сделать результат классом, в конструкторе которого принимается два аргумента, один из которых обязан быть не None, тогда у тебя будет гарантия что никто не сможет собрать инстанс класса в котором оба параметра None.
С первой частью я и не спорил, тут мой косяк, это да, везде плохая практика
Со второй частью не совсем согласен, в плане возможных ошибок - как раз в типе указано, что может быть только CrossIdentificationException
и все ее подклассы. И собственно, раницы мажду Union
или tuple
или dataclass
с типизацией принципиальной нет.
А в целом, если тебе прям режет глаз, без б, закоммичу вариант с классом и проверкой в конструкторе. Более того, я уже зарефакторил на класс Result
, но на мой взгляд, лучше не стало)
Со второй частью не совсем согласен, в плане возможных ошибок - как раз в типе указано, что может быть только CrossIdentificationException и все ее подклассы. И собственно, раницы мажду Union или tuple или dataclass с типизацией принципиальной нет.
А в целом, если тебе прям режет глаз, без б, закоммичу вариант с классом и проверкой в конструкторе. Более того, я уже зарефакторил на класс Result, но на мой взгляд, лучше не стало)
Ну я имею ввиду, что если поменять код в соответствии с первой частью, то получится, что ошибки начнут скрываться - возвращаемое значение останется только одно. Я собственно и предлагаю делать не одно возвращаемое значение, а два, примерно как у тебя сейчас)
Между Union и Tuple разница в том, что в union можно забыть проверить на разные типы, а с tuple забыть точно не получится, потому что возвращаемых значений всегда два
Так, ладно, по итогам дебатов. А то я уже в этих ветках потерялся.
async
выпиливаю здесь, где могу, остальное в issueparam
executemany
- отдельная ишью, где повторяю ошибку и решаем, че с ней делатьВсе так, ничего не забыл?
Так, ладно, по итогам дебатов. А то я уже в этих ветках потерялся.
- по
async
выпиливаю здесь, где могу, остальное в issue- по возвращению эксепшенов - перехожу на возвращение класса из юзкейса, остальное в issue
- делаю эксепшены более специальными, чтобы не передавать
param
- мелкие правки по стилю
- по
executemany
- отдельная ишью, где повторяю ошибку и решаем, че с ней делатьВсе так, ничего не забыл?
Вроде норм
async
добавил к ишью рефакторинга https://github.com/HyperLEDA/db-app/issues/167executemany
https://github.com/HyperLEDA/db-app/issues/182
Cross identification use case implementation and testing