-
Notifications
You must be signed in to change notification settings - Fork 365
Description
I've started to write my own linq operators and I have observed the following issues with using @extensionmethod
to install these operators at runtime:
-
It's tiring to add
@extensionmethod
to every operator. In no other Python codebase I've worked with has this pattern been necessary. -
Leads to buggy imports as import errors are only caught at runtime. Previously, missing imports for functions would have been caught at compile time (and highlighted by IDE).
Even worse, such an import bug may never be identified if you happen to import another module first which does import and install
my_op
. -
Doesn't play well with static code analysers/IDEs (I'm using PyCharm) which is annoying and reduces productivity:
-
Pollutes the
Observable
namespace massively. Having access to all operators in one class is akin to putting all your functions into one file. Sooner or later we're going to run out of sensible names and there's going to be a clash.- This is made worse by the use of aliases: I wrote my own time-weighted aggregation operator and called it
aggregate
, only to find that it didn't work. It was only later that I realised the nameaggregate
was already used as an alias forreduce()
. - This pattern also doesn't make use of Python's duck typing. Before using my operators I have to make sure it's installed for the classes on which I might want to invoke them.
- This is made worse by the use of aliases: I wrote my own time-weighted aggregation operator and called it
-
violates PEP20
There should be one-- and preferably only one --obvious way to do it.
Should I do
observable.select(lambda x: x + 1)
orselect(observable, lambda x: x + 1)
?
So is it really Pythonic to continue using linq operators instead of plain old functions? I.e. instead of observable.map(lambda x: x + 1)
might I suggest something rx.map(lambda x: x + 1, observable)
(which is more consistent with baselib map
and therefore more obvious to newcomers)?