Python Forum
Need your opinions on my experimental library based on RxPy
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Need your opinions on my experimental library based on RxPy
#1
Hi, everyone! My first post here :)

I need opinions on my experimental library that I've been working, and it'd be great if I could get a few advices on how to write better/idiomatic Python code also. By the way, I also posted the same question on Reddit's r/python, so you can reply there instead, if you like.

Recently, I started learning Python and the language's 'descriptor' feature gave me an idea about a new style of programming, so I'd like to see if it's indeed a useful idea or not by asking seasoned Python programmers here.

I've been trying to find a way to integrate some of the Functional Programming(FP) principles in an Object-Oriented Programming context seamlessly.

And I think ReactiveX could be a key to achieve this elusive goal, as it can be used to compose declarative pipelines of data, instead of manipulating it in an imperative style, as it often falls under criticism with the traditional OOP approach. In short, I think we can make a class an eligible participant in such a pipeline if we declare every property in a class as 'Observable[T]'.

The problem with this approach, however, is that it is often desirable or necessary to step across the Rx boundary if we are to build a complex system using this principle.

If we are dealing with actual asynchronous data sources, like a Tweet stream, for instance, we can write the whole program using only Rx pipelines. However, if we are to treat Observables as properties in OOP, and try to use it for everything that may change over time, it can be problematic.

Say, you created a character class in a game project and imagine all of its properties are expressed as Observable[T]. It would mean you have no way to know its current properties like HP, or level unless you subscribed to every single of them beforehand, which would result in a lot of boilerplate code.

So, I made a library to solve this problem and the below code snippet demonstrates its typical usage:

class Fixture:
    value = rv.from_value(1)

    doubled = rv.map(value)(ops.map(lambda v: v * 2))

    numbers = rv.combine(value, doubled)(lambda o: rx.combine_latest(*o))

    combined = rv.combine_latest(value, doubled)(ops.map(lambda v: f"value = {v[0]}, doubled = {v[1]}"))

    zipped = rv.zip(value, doubled)(ops.map(lambda v: f"{v[0]} * 2 = {v[1]}"))

combined = []
zipped = []

fixture = Fixture()

rv.observe(fixture.zipped).subscribe(zipped.append)
rv.observe(fixture.combined).subscribe(combined.append)

self.assertEqual(1, fixture.value)
self.assertEqual(2, fixture.doubled)
self.assertEqual((1, 2), fixture.numbers)
self.assertEqual("value = 1, doubled = 2", fixture.combined)
self.assertEqual("1 * 2 = 2", fixture.zipped)
self.assertEqual(["value = 1, doubled = 2"], combined)
self.assertEqual(["1 * 2 = 2"], zipped)

fixture.value = 3

self.assertEqual(3, fixture.value)
self.assertEqual(6, fixture.doubled)
self.assertEqual((3, 6), fixture.numbers)
self.assertEqual("value = 3, doubled = 6", fixture.combined)
self.assertEqual("3 * 2 = 6", fixture.zipped)
self.assertEqual(["value = 1, doubled = 2", "value = 3, doubled = 2", "value = 3, doubled = 6"], combined)
self.assertEqual(["1 * 2 = 2", "3 * 2 = 6"], zipped)
In short, it allows accessing a class attribute/property in a few different ways depending on the context. So, if there's an instance of 'Fixture' class 'fixture', its property 'value' can be referenced in the following manner:

'Fixture.value' returns 'ReactiveValue[T]', which is the stateless property instance itself.

'fixture.value' returns 'T', so it can be treated like any other class properties.

'observe(fixture.value)' yields 'Observable[T]', so it can be composed to build a complex Rx pipeline.

And as you can see from the above example, a 'reactive property' can also be declared by composing other properties (or plain Observables), both from the same class or from the parent type. So it supports OOP type polymorphism like ordinary properties.

I've been working on this library as a FOSS project, but I haven't decided if I should take it seriously to add lengthy documentation or code samples to explain the idea. I'm still afraid it may turn out to be just an unuseful idea devised to solve an imaginary problem (namely, that of bridging the gap between OOP and FP using Rx).

So, I'd like to hear opinions from other people who have more experience with Python, or FP in general.

If you are interested, you may want to visit the project page on Github. As a very beginner of Python language, it'd be nice to have some advices and feedbacks on how to write a better, more idiomatic Python code from seasoned programmers here.

Thanks in advance!
Reply
#2
As nobody has given me any feedback, I just gave it a go and made it public by publishing it to PyPI.

The API has been refactored to allow more concise expression and I've also expanded the documentation to give people a better idea of what this library does.

Please feel free to visit the project page and leave me your opinions and criticisms of the library.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  your expert opinions on my matches game delcencen 0 1,705 Jul-13-2020, 08:26 AM
Last Post: delcencen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020