I’m a little unclear how it’s surprising. If you define a function (such as your func2
) that results a constant value that does not depend on the input (or any external state), it must always return that value, exactly as you told it to do. If that value is a single integer literal, then the return value will always be that single integer literal; it will not and cannot magically get changed into an array just because you passed on in, because the return value you defined does not depend on the input.
By contrast, if you define a function where the return value depends on the input (such as your func1
), then the type and value you get back may vary depending on what you input. In this case, as @franklinvp mentioned, adding or multiplying the input NumPy array by a scalar results in a NumPy array with all the elements of the original added or multiplied by the scalar.
This may seem a little magical, but in Python, most of the operators (+
, *
. etc) are just syntactic sugar for calling special double underscore (dunder) methods on the objects involved, so objects can effectively “redefine” these operators to mean what they want.
You can create your own class that demonstrates a simple example of this:
class Vector:
def __init__(self, *values):
self._values = list(values)
def __add__(self, other):
return Vector(*(value + other for value in self._values))
def __mul__(self, other):
return Vector(*(value * other for value in self._values))
# Right hand side variants
def __radd__(self, other):
return self.__add__(other)
def __rmul__(self, other):
return self.__mul__(other)
# Etc for any other desired operators
# So str(), repr(), implict and explict printing work
def __str__(self):
return str(self._values)
def __repr__(self):
return f"Vector({', '.join(repr(value) for value in self._values)})"
Now, you can perform addition and multiplication on an instance of your Vector
with a scalar and it will return a Vector
with the operation “broadcast” to all the elements, like NumPy does:
In [1]: vec = Vector(1, 2, 3)
In [2]: vec * 5
Out[2]: Vector(5, 10, 15)
In [3]: vec * 2 + 1
Out[3]: Vector(3, 5, 7)
In [4]: 7 + 0 * vec
Out[4]: Vector(7, 7, 7)
If you call your func1
and func2
on this Vector
vec
, you’ll get the same result as on the NumPy array above:
func1(vec)
Out[27]: Vector(7, 7, 7)
func2(vec)
Out[28]: 7