Skip to content
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

Iterable as a second argument #15

Open
wjaskowski opened this issue Mar 16, 2018 · 4 comments
Open

Iterable as a second argument #15

wjaskowski opened this issue Mar 16, 2018 · 4 comments

Comments

@wjaskowski
Copy link

It is possible to easily achieve something like:

def f(x, y):
    r = 0
    for i in range(100000000000):
        r += i
    return r
parmap.map(f, x=1, y=range(100))

?

@zeehio
Copy link
Owner

zeehio commented Mar 16, 2018

Yes, just use a helper function:

def g(y, x):
    return f(x, y)

parmap.map(g, range(100), x=1)

There is also https://docs.python.org/3.6/library/functools.html#functools.partial

If you have a suggestion for an alternative API, feel free to suggest it.

@wjaskowski
Copy link
Author

wjaskowski commented Mar 16, 2018 via email

@zeehio
Copy link
Owner

zeehio commented Mar 17, 2018

I have some concerns with that approach:

There is a use case where an extra argument is an iterable:

def times2(xlimits, x):
    xmin = xlimits[0]
    xmax = xlimits[1]
    if x < xmin:
        x = xmin
    if x > xmax:
        x = xmax
    return 2*x

parmap.map(times2, xlimits = [0, 5], x = range(10))

It would be harder (impossible) in this case for parmap to guess that the iterable argument is the second one.

It is then possible to modify times2 so as if xlimits is a single number it assumes it is a single boundary (xmax) and, if it is a two element list then it follows the previous definition:

def times2b(xlimits, x):
    if isinstance(xlimits, (int, float)):
        xmin = -float('Inf')
        xmax = xlimits
    else: 
        xmin = xlimits[0]
        xmax = xlimits[1]
    if x < xmin:
        x = xmin
    if x > xmax:
        x = xmax
    return 2*x

parmap.map(times2, xlimits = 5, x = range(10))
parmap.map(times2, xlimits = [0, 5], x = range(10))

Here with your API proposal, the first call would work as expected, the second one would not do what we wanted. It could surprise parmap users.

For an interactive use (such as in a notebook) the approach you suggest is good, in most cases it will do what we want and we will like it.

However, parmap users may start to use that syntax in their python packages, and their users may use those packages in surprising ways that can lead to parmap iterating in the wrong argument.

https://en.m.wikipedia.org/wiki/Principle_of_least_astonishment

Besides, by reading at your first example I could also think that you wanted to compute f(x=1, y=range(100)) and that you meant:
parmap.map(f, x=[1], y=range(100)). Currently we can catch the error while with your API we would get a surprising result.

What would you think of an API like:

parmap.map(f, x=1, y=range(100), pm_iter="y")

?

@wjaskowski
Copy link
Author

My idea was that

parmap.map(times2, xlimits = [0, 5], x = range(10))

should simply call times2 with the given arguments but

parmap.map(times2, range(10), xlimits = [0, 5])
parmap.map(times2, iterable=range(10), xlimits = [0, 5])

could call times2 with different values of x.
Do you find it surprising?

At the same time, I like

parmap.map(f, x=1, y=range(100), pm_iter="y")

It is nicely explicit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants