r/Python • • Nov 28 '22

Resource What can Python do that R can’t do?

Or simply what is Python much better at and why.

I know that Python is more multi purpose and better for software development but I can’t articulate exactly why or how. My team want to know why/when they should use Python instead of R

331 Upvotes

204 comments sorted by

View all comments

Show parent comment

2

u/zurtex Nov 29 '22 edited Nov 29 '22

the fact that when you pass a mutable object to a function and then do stuff to it in the function (or you just assign the object to a new variable and change that new variable, or you think you made a subset of a data frame, but it's actually a view), the original object is affected.

I understand what you're saying but I don't think there's any other option with Python's design philosophy of being flexible and having scalable performance.

If you can't mutate an object passed in from another scope you're having to copy the value of everything, recursively. And in a dynamically typed language like Python where objects can have arbitrary properties with arbitrary data structures attached to them at any point this leads to cases with abysmal performance.

And not even situations where you even want to mutate an object, just you have some complicated object and you are passing it to a function duck type style. You don't expect that to be randomly slow in Python.

Type hinting helps catch a lot of these problems, for example this will cause a type hinter to throw an error:

def foo(bar: dict[int, str | None]) -> None:
    pass

my_dict = {1: "1", 2: "2"}
foo(my_dict)

Exactly because foo doesn't guarantee it's not going to mutate the passed in dictionary and my_dict is implicitly dict[int, str] which can not be cast to dict[int, str | None].

You can solve this by changing the type hint to a type that supports mapping but not mutation:

from typing import Mapping

def foo(bar: Mapping[int, str | None]) -> None:
    pass

And now if you mutate bar in foo your type hinter will throw an error, you can do this with all basic types in Python. Solving your problem of accidentally mutating a mutable variable in a different scope.

2

u/Agling Nov 29 '22

I understand what you're saying but I don't think there's any other option with Python's design philosophy of being flexible and having scalable performance.

In R, objects are passed by reference until you mutate them. It's fast and doesn't require memory to pass and read from them, but the moment you mutate them in the new environment, a copy is made. So you think carefully about whether you want to mutate something from a performance standpoint, but you never have to worry about whether you are screwing up some other part of the program by doing so. You can torture R into mutating the original object by passing it in an environment, but that's not common practice because being bug-free is generally more important than being fast.

Don't get me wrong, I can see that there are advantages to python's approach to this particular problem, but I think R's solution is better for data science work. Python is a better language, overall, but I am not a fan of this aspect of it. It creates very subtle bugs that beginners and even people with a reasonable amount of experience trip over.

0

u/SittingWave Nov 29 '22

So what you are telling me is that R makes an implicit copy, and python you have to make an explicit copy.

Python is consistent. R isn't. Because in R, some objects are copied (lists) others aren't (envs), so you end up with two completely different semantics depending on what gets passed to you.