101

Numpy provides both np.absolute and the alias np.abs defined via

from .numeric import absolute as abs

which seems to be in obvious violation of the zen of python:

There should be one-- and preferably only one --obvious way to do it.

So I'm guessing that there is a good reason for this.

I have personally been using np.abs in almost all of my code and looking at e.g. the number of search results for np.abs vs np.absolute on Stack Overflow it seems like an overwhelming majority does the same (2130 vs 244 hits).

Is there any reason i should preferentially use np.absolute over np.abs in my code, or should I simply go for the more "standard" np.abs?

Jonas Adler
  • 10,365
  • 5
  • 46
  • 73

2 Answers2

97

It's likely because there a built-in functions with the same name, abs. The same is true for np.amax, np.amin and np.round_.

The aliases for the NumPy functions abs, min, max and round are only defined in the top-level package.

So np.abs and np.absolute are completely identical. It doesn't matter which one you use.

There are several advantages to the short names: They are shorter and they are known to Python programmers because the names are identical to the built-in Python functions. So end-users have it easier (less to type, less to remember).

But there are reasons to have different names too: NumPy (or more generally 3rd party packages) sometimes need the Python functions abs, min, etc. So inside the package they define functions with a different name so you can still access the Python functions - and just in the top-level of the package you expose the "shortcuts". Note: Different names are not the only available option in that case: One could work around that with the Python module builtins to access the built-in functions if one shadowed a built-in name.

It might also be the case (but that's pure speculation on my part) that they originally only included the long-named functions absolute (and so on) and only added the short aliases later. Being a large and well-used library the NumPy developers don't remove or deprecate stuff lightly. So they may just keep the long names around because it could break old code/scripts if they would remove them.

MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • 8
    Hmm... what you write is certainly true for `abs`/`absolute`, but `np.maximum` and `np.max` are not identical. The former operates element-wise on two arrays and the latter is a reduction operation along an axis of one input. – MB-F Jul 31 '17 at 12:17
  • @kazemakase You're right. I was thinking about the wrong functions. I corrected the names (`amax` and `amin` instead of `maximum` and `minimum`). Thank you :) – MSeifert Jul 31 '17 at 12:21
  • 1
    Yep, `np.amax is np.max` :) (I didn't even know about `amax`/`amin`) – MB-F Jul 31 '17 at 12:22
  • 2
    _"But there are reasons to have different names"_ That's not actually the best way how to avoid name shadowing, is it? One can simply prepend a module name in front of the function name. – Jeyekomon Apr 26 '18 at 13:31
  • 2
    @Jeyekomon I didn't mean to imply it's the best approach or even a good one. It's just one possibility. I guess the question how to approach that simply cannot be changed anymore because NumPy tries to be backwards-compatible. So any discussion about which one would be better/the best makes no sense in that context anymore. – MSeifert Apr 26 '18 at 14:20
12

There also is Python's built-in abs(), but really all those functions are doing the same thing. They're even exactly equally fast! (This is not the case for other functions, like max().)

enter image description here

Code to reproduce the plot:

import numpy as np
import perfplot


def np_absolute(x):
    return np.absolute(x)


def np_abs(x):
    return np.abs(x)


def builtin_abs(x):
    return abs(x)


b = perfplot.bench(
    setup=np.random.rand,
    kernels=[np_abs, np_absolute, builtin_abs],
    n_range=[2 ** k for k in range(25)],
    xlabel="len(data)",
)
b.save("out.png")
b.show()
Nico Schlömer
  • 53,797
  • 27
  • 201
  • 249
  • I suspect the identical performance is due to numpy arrays using the `__abs__` magic method, which `abs()` calls if defined. – Kyle Carow Mar 10 '23 at 17:24