from numpy import *
arr = array([1,2,3,4])
Here array() is a function so arr is not an object (I hope so).
Because an object is created using following syntax:
obj = class_name()
and array() is afunction
For eg :-
a = int(1) here int is a class
here a is an object
and i know python use object literal for our convenience hence we write it as a = 1
from numpy import *
arr = array([1,2,3,4])
But in the above case how arr is treated as an object I am telling this because
from numpy import *
arr = array([1,2,3,4])
print(arr.dtype)
In the above code we can see dtype() is called with the help of arr as an object
How is this possible ?
I just want to know how arr is treated as an object ?
Related
Numpy has a type hint ArrayLike that is supposed to cover pretty much all objects you might want to convert to a numpy array (e.g. lists, objects implementing __array__ and some more).
It can be used like any type hint:
from numpy.typing import ArrayLike
def some_func(a : ArrayLike):
print(a)
But it might happen that you want check whether an object is an ArrayLike during runtime:
def some_func(a):
if type(a) == ArrayLike: # Does not work
print(a)
if issubclass(a, ArrayLike): # Raises an error
print(a)
if isinstance(a, ArrayLike): # Raises an error
print(a)
Is something like this possible using ArrayLike? Or should I use another method?
MWE:
import numpy as np
from numpy.typing import ArrayLike
class MyArrayLike:
def __array__(self, dtype = None):
return np.asarray([0, 1])
def some_func(a : ArrayLike):
if type(a) == ArrayLike:
print(a)
# if issubclass(a, ArrayLike):
# print(a)
# if isinstance(a, ArrayLike):
# print(a)
a = MyArrayLike()
some_func(a)
I defined a method below that is supposed to take 5 integer/float values as input, and one list object (the lst parameter) and return only the positive solutions for r in the equation F. The formula for F should return a list where each element is multiplied/subtracted using the equation given.
I got the error Error : Can't multiply sequence by non-int of type 'Mul' mentioned above. What am I missing?
from sympy import *
from math import pi
class solarheating:
def circular_rr(T0,T,lst,m,Cp,Eg):
r = var('r')
F = T0+pi*r**2*Eg/(m*Cp)*lst-T
r = solve(F,r)
return r[1]
lst = [0,0.25,0.5,0.75,1.0,1.25]
a = circular_rr(20,15,lst,.24,4.2,.928)
print(a)
You forgot to pass the instance of the object (or self) on which the code is being called to the method. Since there was no self, you were getting the non-int error, because T0 became self, T became T0, and then your lst was being used as T. Since you cannot subtract a int from a list, this produced an error.
Here's the corrected code.
from sympy import *
from math import pi
class solar heating:
def circular_rr(self,T0,T,lst,m,Cp,Eg):
r = var('r')
F = T0+pi*r**2*Eg/(m*Cp)*lst-T
r = solve(F,r)
return r[1]
lst = [0,0.25,0.5,0.75,1.0,1.25]
my_instance = solarheating()
a = my_instance.circular_rr(20,15,lst,.24,4.2,.928)
print(a)
The reason you need to use self is because Python does not use the #syntax to refer to instance attributes. The method is called on the instance you pass in the self attribute. You don't actually write instance methods in Python; what you write is class methods which (must) take an instance as a first parameter. And therefore, you’ll have to place the instance parameter somewhere explicitly.
Edit:
Besides the obvious self error I've described above, you're multiplying a float by a list. That's what's causing the can't multiply sequence by non-int of type 'Mul' error.
If you want to multiply each item in the list by the float, your corrected method code will be:
def circular_rr(self,T0,T,lst,m,Cp,Eg):
r = var('r')
temp_val = T0+pi*r**2*Eg/(m*Cp)
F = [x*temp_val-T for x in lst]
r = solve(F,r)
return r[1]
Using numpy and matplotlib it seems quite common that functions allow both a number (float or int) or a numpy array as argument like this:
import numpy as np
print np.sin(0)
# 0
x = np.arange(0,4,0.1)
y = np.sin(x)
In this example I call np.sin once with an integer argument, and once with a numpy array x. I now want to write a function that allows similar treatment, but I don't know how. For example:
def fun(foo, n):
a = np.zeros(n)
for i in range(n):
a[i] = foo
return a
would allow me to call fun like fun(1, 5) but not like fun(x, 5). My actual calculation is much more complicated, of course.
How can I initialize a such that I can have both simple numbers or a whole array of numbers as elements?
Thanks a lot for your help!
Builtin numpy functions often start with a
def foo(a, ...):
a = np.asarray(a)
...
That is, they transform the input argument(s) to array (no copy if it is already an array). The allows them to work with scalars and lists.
Once the argument is an array it has a shape and can be broadcasted against other arguments.
In your example, it's unclear what is supposed to happen when foo is an array
def fun(foo, n):
a = np.zeros(n)
for i in range(n):
a[i] = foo
return a
a is initialized as a dtype float array. That means a[i]=foo works only if foo is a single element number (scalar, possibly a single element array). If foo is an array with more than one value you probably get an error about attempting to set an element with a sequence.
a[i] is short for a[i,...]. That is it indexes on the 1st dimension. So if a was initialed correctly it could accept arrays as inputs (subject to broadcasting rules).
If a was initialed as np.zeros(n, dtype=object), then a[i]=foo will work with anything, since it a just contains pointers to Python objects.
np.frompyfunc is a way of generating an array from a function. But it returns an array of dtype=object. np.vectorize uses that but gives you more control over the output type. But both work with scalars. An array, if given as argument, is passed element by element to the function.
You need a to inherit the dimensions of foo:
def fun(foo, n):
a = np.zeros((n,) + np.shape(foo))
for i in range(n):
a[i] = foo
return a
You can use type identification :
import numpy as np
def double(a):
if type(a)==int:
return 2*a
elif type(a)==float:
return 2.0*a
elif type(a)==list:
return [double(x) for x in a]
elif type(a)==np.ndarray:
return 2*a
else:
print "bad type"
print double(7)
print double(7.2)
print double([2,9,7])
print double(np.array([[9,8],[2,3]]))
result :
>14
>14.4
>[4, 18, 14]
>[[18 16]
[ 4 6]]
with eventually a recursive treatement as I did on list
Is there a way to disable silent conversions in numpy?
import numpy as np
a = np.empty(10, int)
a[2] = 4 # OK
a[3] = 4.9 # Will silently convert to 4, but I would prefer a TypeError
a[4] = 4j # TypeError: can't convert complex to long
Can numpy.ndarray objects be configured to return a TypeError when assigning any value which is not isinstance() of the ndarray type?
If not, would the best alternative be to subclass numpy.ndarray (and override __setattr__ or __setitem__)?
Unfortunately numpy doesn't offer this feature in array creation, you can set if casting is allowed only when you are converting an array (check the documentation for numpy.ndarray.astype).
You could use that feature, or subclass numpy.ndarray, but also consider using the array module offered by python itself to create a typed array:
from array import array
a = array('i', [0] * 10)
a[2] = 4 # OK
a[3] = 4.9 # TypeError: integer argument expected, got float
Just an idea.
#Python 2.7.3
>>> def test(value):
... if '.' in str(value):
... return str(value)
... else:
... return value
...
>>> a[3]=test(4.0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for long() with base 10: '4.0'
I've recently run into issues when creating Numpy object arrays using e.g.
a = np.array([c], dtype=np.object)
where c is an instance of some complicated class, and in some cases Numpy tries to access some methods of that class. However, doing:
a = np.empty((1,), dtype=np.object)
a[0] = c
solves the issue. I'm curious as to what the difference is between these two internally. Why in the first case might Numpy try and access some attributes or methods of c?
EDIT: For the record, here is example code that demonstrates the issue:
import numpy as np
class Thing(object):
def __getitem__(self, item):
print "in getitem"
def __len__(self):
return 1
a = np.array([Thing()], dtype='object')
This prints out getitem twice. Basically if __len__ is present in the class, then this is when one can run into unexpected behavior.
In the first case a = np.array([c], dtype=np.object), numpy knows nothing about the shape of the intended array.
For example, when you define
d = range(10)
a = np.array([d])
Then you expect numpy to determine the shape based on the length of d.
So similarly in your case, numpy will attempt to see if len(c) is defined, and if it is, to access the elements of c via c[i].
You can see the effect by defining a class such as
class X(object):
def __len__(self): return 10
def __getitem__(self, i): return "x" * i
Then
print numpy.array([X()], dtype=object)
produces
[[ x xx xxx xxxx xxxxx xxxxxx xxxxxxx xxxxxxxx xxxxxxxxx]]
In contrast, in your second case
a = np.empty((1,), dtype=np.object)
a[0] = c
Then the shape of a has already been determined. Thus numpy can just directly assign the object.
However to an extent this is true only since a is a vector. If it had been defined with a different shape then method accesses will still occur. The following for example will still call ___getitem__ on a class
a = numpy.empty((1, 10), dtype=object)
a[0] = X()
print a
returns
[[ x xx xxx xxxx xxxxx xxxxxx xxxxxxx xxxxxxxx xxxxxxxxx]]