-
Notifications
You must be signed in to change notification settings - Fork 362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is it really Pythonic to continue using linq operators instead of plain old functions? #94
Comments
Thanks for interesting ideas. RxPY is a port of Reactive Extensions for Python, thus it makes sense to keep it as close to the original implementation as possible. But I agree that it's a problem that code analyzers such as PyCharm and VS does not understand the core library code. For example RxJava implements all operators in a single class. Python is also an object-oriented language, and I don't think it makes sense to use a functional programming style in Python. xs = source.select(lambda x: x*42).where(lambda x: x>10).scan(reducer) vs. xs = scan(where(select(source, lambda x: x*42), lambda x: x>10), reducer) I guess none of them are Pythonic. For that we would probably need an async comprehension expression or something. Even Guido wanted to remove |
I see your point, Dag. I guess the root of my concern is that the current design violates the Open/closed principle: If I want to add my own linq operators, I shouldn't have to inject/modify the base
I love the itertools library and I envisage linq should do for
But that's because you can't define free-floating functions in Java -- all functions are methods defined on some class. I don't think that fits well with Python. |
An alternative would be to have operators as free-floating functions as you describe, but also provide a wrapped version of Observable with methods similar to Underscore.js. You would have two ways of doing the same thing, but I think it would be acceptable since the developer decides to use "wrapped" observables or not. |
@mchen402 Here is a first try on an Underscore.js like version where you have the choice to use plain functions or To write "extension methods" you either:
PS: Only works for |
Not that happy with the https://github.com/ReactiveX/RxPY/blob/feature/chained/playground/chained.py Anyways, the idea is that we can now create a core library out of plain functions and ABCs, and build # Functional style like itertools but with pipelining and partially applied functions
xs = rx.from_([1, 2, 3, 4, 5])
ys = xs | rx.filter(lambda x: x > 2) | rx.map(lambda x: x*10)
ys.subscribe(print) Sounds like something that could become RxPY v2.0 |
Nice, so you would do I presume if John Doe later comes along and writes |
No more |
Many of the ideas from this issue have resulted in https://github.com/dbrattli/aioreactive It's not Rx as in Observables and Rx.NET, but many of the same ideas. Hopefully more Pythonic and plain old functions. |
FYI, I filed a bug with PyCharm asking if it's possible to detect and capture dynamically added functions. |
Pleaze vote it up if you'd like to see it prioritized. |
+1 for
This is really important for ergonomics. A big reason I don't like using pandas in production is that I can't create custom DataFrame subclasses and use on the method-chaining API. Using a container class like |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
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:
my_rx
needs to be run in order to installmy_op
at runtime -- falsely flags the import as unnecessaryPollutes 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.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()
.violates PEP20
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 somethingrx.map(lambda x: x + 1, observable)
(which is more consistent with baselibmap
and therefore more obvious to newcomers)?The text was updated successfully, but these errors were encountered: