Почему встроенные функции, такие как abs, работают в массиве numpy?

Я очень удивлен тем, что abs работает в массиве numpy, но не в списках. Почему это?

import numpy as np

abs(np.array((1,-2)))
array([1, 2])

abs([1,-1])
TypeError: bad operand type for abs(): 'list'

Кроме того, встроенные функции, такие как sum, также работают с массивом numpy. Думаю, это потому, что массив numpy поддерживает __getitem__? Но в случае abs, если он зависит от __getitem__, он должен работать и для списка, но это не так.

Ответ 1

Это потому, что numpy.ndarray реализует метод __abs__(self). Просто предоставьте его для своего собственного класса, и abs() будет волшебным образом работать. Для не встроенных типов вы также можете предоставить это средство после факта. Например.

class A:
    "A class without __abs__ defined"
    def __init__(self, v):
        self.v = v

def A_abs(a):
    "An 'extension' method that will be added to `A`"
    return abs(a.v)

# Make abs() work with an instance of A
A.__abs__ = A_abs

Однако это не будет работать для встроенных типов, таких как list или dict.

Ответ 2

abs функция ищет метод __abs__.

вы также можете, подобно numpy, реализовать метод __abs__ в своих классах, поэтому abs будет работать с ними.

то есть.

class A(object):
    def __abs__(self):
        return 8

>>> a= A()
>>> abs(a)
8
>>>

Ответ 3

sum работает с итерабельными, такими как массивы списка или numpy.

abs работает с значениями, которые определяют метод __abs__, например числа или numpy.arrays:

>>> x = -1
>>> x.__abs__()
1

>>> class A(object):
...     def __abs__(self):
...         return 12
>>> a = A()
>>> abs(a)
12

list не определяют этот метод, хотя вы можете использовать понимание карт или списков (map(abs, [1, -1]) и [abs(x) for x in [1,-1]] соответственно) для того, что вам нужно. Если вам нравится overkill, вы также можете выбрать список подкласса и определить numpy-like __abs__ (но, как правило, это понимание является более предпочтительным)