I have a class MyClass which stores an integer a. I want to define a function inside it that takes a numpy array x of length a, but I want that if the user does not pass in anything, x is set to a random array of the same length. (If they pass in values of the wrong length, I can raise an error). Basically, I would like x to default to a random array of size a.
Here is my attempt at implementing this
import numpy as np
class MyClass():
def __init__(self, a):
self.a = a
def function(self, x = None):
if x == None:
x = np.random.rand(self.a)
# do some more functiony stuff with x
This works if nothing is passed in, but if x is passed in I get ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() i.e. it seems numpy doesn't like comparing arrays with None.
Defining the default value inline doesn't work because self is not in scope yet.
Is there a nice pythonic way to achieve this? To sum up I would like the parameter x to default to a random array of a specific, class-defined length.
As a rule of thumb, comparisons of anything and None should be done with is and not ==.
Changing if x == None to if x is None solves this issue.
class MyClass():
def __init__(self, a):
self.a = a
def function(self, x=None, y=None):
if x is None:
x = np.random.rand(self.a)
print(x)
MyClass(2).function(np.array([1, 2]))
MyClass(2).function()
# [1 2]
# [ 0.92032119 0.71054885]
Related
When using optimization (e.g. brentq), the input is always an array of items. However, sometimes it is necessary to use a comparator function like >= in object function. Then, python is not able to evaluate those values.
For example:
def f(x):
if x > 0:
return x
if x <= 0:
return -x
optimize.brentq(f,-1,1)
Then we will have the error: The truth value of an array with more than one element is ambiguous.
In general, how to avoid this error?
If f is what you actually need, use np.abs instead. If it's a dummy example, use something like this instead:
def f(x):
return np.where(x>0, x, -x)
In general change
def f(x):
if condition(x):
return f1(x)
else:
return f2(x)
to
def f(x):
return np.where(condition(x), f1(x), f2(x))
keeping in mind that for non trivial conditions, your implementation should still be able to handle vectors... (i.e. if x is a vector condition(x) should return a vector of the same size as x)
Is it possible to write a function such that in every call it save data; for example- the following function takes two arguments x & y; where x is a data and y is the array size.
Call the function first time, it would create y dimensional array, fill the first position with x value and in the second call it would fill the 2nd position of the array and continue and it will return a average when at least 2 values are in that array. The array size would be fixed, if call the function more than y times, it will delete first data (FIFO).
def storedata(x,y):
return z
you can use global variables to keep your data in them and call them between your functions.
check out this page: What is the pythonic way of saving data between function calls? maybe solve your problem if you want to use the class and attribute solution.
You should use a class when you want to store data.
An small example is given below, but please look online for tutorial and examples to fully understand the working of classes and OOP in python.
class Storedata:
def __init__(self, x, y):
self.arr = []
self.max_arr_size = y
self.add_data(x)
def add_data(self, x):
if len(self.arr) < self.max_arr_size:
self.arr.append(x)
def __call__(self):
return sum(self.arr)/len(self.arr)
storedata = Storedata(3, 5)
print(storedata.arr)
>>> [3]
print( storedata() )
>>> 3.0
storedata.add_data(5)
print( storedata() )
>>> 4.0
Thanks everyone for the solutions. Using a class is a good way but I think I was looking for the following code.
def storedata(x, y):
if not hasattr(storedata, 'z'):
storedata.z = np.zeros(y, dtype=float)
storedata.z = np.roll(storedata.z, 1)
storedata.z[0] = x
storedata.z[storedata.z == 0] = np.nan
return storedata.z, np.nanmean(storedata.z)
for i in range(1, 11):
print(storedata(x=i, y=10))
Lets say I have a class Vector2D that take x and y components. Because I have no interest in vectors with both components equal to zero, I want to prevent the object with both parameters passed equal to zero from being created in the first place and return None instead.
You could rename your class to RealVector2D and replace it with a new function:
def Vector2D(x, y):
if x == 0 and y == 0:
return None
return RealVector2D(x, y)
You can use a factory function to verify that your parameters are not zero, thn return an instance of Vector2D, or raise an Error:
As mentioned in the comments by #jasonsharper, returning None is not a good idea, better to return an explicit error.
class NullVectorError(ValueError):
pass
def make_non_null_vector(x: float, y: float) -> vector2D:
if x and y:
return Vector2D(x, y)
raise NullVectorError('the parameters x:{x}, and y:{y}, cannot be both equal to zero')
Is it possible to make a class in python that can be indexed with square brackets but not derived from a different indexed type?
I'm interested in making a class with optional indexes, that would behave like this:
class indexed_array():
def __init__(self, values):
self.values = values
def __sqb__(self, indices): #This is a made up thing that would convert square brackets to a function
if len(indices) == 2:
return self.values[indices[0]][indices[1]]
elif len(indices) == 1:
return self.values[indices[0]][0]
myarray = indexed_array([[1,2,3], [4,5,6], [7,8,9]])
print myarray[1, 1] # returns 5
print myarray[1] # returns 4
Is there a real method like my __sqb__? Alternatively, can you index a custom class another way?
You are need to implement __getitem__. Be aware that a single index will be passed as itself, while multiple indices will be passed as a tuple.
Typically you might choose to deal with this in the following way:
class indexed_array:
def __getitem__(self, indices):
# convert a simple index x[y] to a tuple for consistency
if not isinstance(indices, tuple):
indices = tuple(indices)
# now handle the different dimensional cases
...
I made this class that computes some operations for 3d vectors, is there anyway I can change the code so that it computes the same operations but for vectors of any dimension n?
import sys
class Vector:
def __init__(self,x,y,z):
self.x= x
self.y= y
self.z= z
def __repr__(self):
return "(%f,%f,%f)"%(self.x,self.y,self.z)
def __add__(self,other):
return (self.x+other.x,self.y+other.y,self.z+other.z)
def __sub__(self,other):
return (self.x-other.x,self.y-other.y,self.z-other.z)
def __norm__(self):
return (self.x**2+self.y**2+self.z**2)**0.5
def escalar(self,other):
return (self.x*other.x+self.y*other.y+self.z*other.z)
def __mod__(self,other):
return (self.x%other.x,self.y%other.y,self.z%other.z)
def __neg__(self):
return (-self.x,-self.y,-self.z)
As an example, for a n dimensional vector, something like
class Vector:
def __init__(self, components):
self.components = components # components should be a list
def __add__(self, other):
assert len(other.components) == len(self.components)
added_components = []
for i in range(len(self.components)):
added_components.append(self.components[i] + other.components[i])
return Vector(added_components)
def dimensions(self):
return len(self.components)
would be possible. Note that the __add__ override returns a new Vector instance, not a tuple as in your case. Then adapt your other methods likewise.
There are more 'clever' ways of adding elements from two lists, into a third. You should really not do it this way if performance is an issue though (or in any other case but an exercise, IMO). Look into numpy.
Use a list to store the coefficients rather than explicit variables. For negating, adding, subtracting etc. you just iterate over the lists.
In terms of initialisation, you need to use *args for the input. Have a look at this post for an explanation of how it works: https://stackoverflow.com/a/3394898/1178052