I don't understand why this code doesn't work:
import numpy as np
class Normalizer:
def __init__(self,x):
self.x = x
def mean(self):
return np.sum(self.x)/np.size(self.x)
def mean_zero(self):
return self.x - self.x.mean()
def new_calc(self):
return self.x.mean_zero()
a = np.random.randint(150,200,(5,8))
heights = Normalizer(a)
print(a)
print(heights.mean())
print(heights.mean_zero())
print(heights.mean_zero().mean())
print(heights.new_calc())
It executes heghts.mean_zero() correctly but in the method def new_calc(self) it doesn't execute it. It would be great if someone could explain that to me. Thanks!
I don't understand why this code doesn't work:
if you run the following code it will throw an error:
AttributeError: 'numpy.ndarray' object has no attribute 'mean_zero'
locate the problem, the only place where mean_zero has been called is new_calc method. So, first step done.
analyze, if you look at Normalize class it has one attribute x which is of the type numpy.ndarray. If you carefully read the error message it says that ndarray type doesn't have the attribute mean_zero. On the other hand you have mean_zero method defined in your class and that is the one you should call.
These two steps leads to conclusion that the problem is in new_calc method:
def new_calc(self):
return self.mean_zero() #(wrong)return self.x.mean_zero()
I am not sure what x from the __init__ is but it is very likely that you actually want to call mean_zero in new_calc in the context of self variable (the same object):
def new_calc(self):
return self.mean_zero()
Insted of self.x.mean_zero() write self.mean_zero()
import numpy as np
class Normalizer:
def __init__(self,x):
self.x = x
def mean(self):
return np.sum(self.x)/np.size(self.x)
def mean_zero(self):
return self.x - self.mean()
def new_calc(self):
return self.mean_zero()
a = np.random.randint(150,200,(5,8))
heights = Normalizer(a)
print(a)
print(heights.mean())
print(heights.mean_zero())
print(heights.mean_zero().mean())
print(heights.new_calc())
You're initializing Normalizer with 'a', which is the output of np.random.randint, which returns a numpy.ndarray object.
In the new_calc method you are attempting to call the mean_zero method of the ndarray object, but ndarray has no such method. mean_zero is a method on Normalizer, but self.x is not of type Normalizer.
I'm not sure what this code new_calc is supposed to do. If you can make that clearer, I may be able to provide more assistance.
The culprit:
def new_calc(self):
return self.x.mean_zero()
The reason:
self.x is an attribute of the Normalizer class. So if heights is an instance of the Normalizer class, then heights.x is the self.x.
The answer:
def new_calc(self):
return self.mean_zero()
The justification:
AttributeError: 'numpy.ndarray' object has no attribute 'mean_zero'
ndarray has no such method. mean_zero is a method of Normalizer
Related
I have a three dimensional dataset where the 1st dimension gives the type of the variable and the 2nd and 3rd dimensions are spatial indexes. I am attempting to make this data more user friendly by creating a subclass of ndarray containing the data, but with attributes that have sensible names that point to the appropriate variable dimension. One of the variable types is temperature, which I would like to represent with the attribute .T. I attempt to set it like this:
self.T = self[8,:,:]
However, this clashes with the underlying numpy attribute for transposing an array. Normally, overriding a class attribute is trivial, however in this case I get an exception when I try to re-write the attribute. The following is a minimal example of the same problem:
import numpy as np
class foo(np.ndarray):
def __new__(cls, input_array):
obj = np.asarray(input_array).view(cls)
obj.T = 100.0
return obj
foo([1,2,3,4])
results in:
Traceback (most recent call last):
File "tmp.py", line 9, in <module>
foo([1,2,3,4])
File "tmp.py", line 6, in __new__
obj.T = 100.0
AttributeError: attribute 'T' of 'numpy.ndarray' objects is not writable
I have tried using setattr(obj, 'T', 100.0) to set the attribute, but the result is the same.
Obviously, I could just give up and name my attribute .temperature, or something else. However .T will be much more eloquent for the subsequent mathematical expressions which will be done with these data objects. How can I force python/numpy to override this attribute?
For np.matrix subclass, as defined in np.matrixlib.defmatrix:
#property
def T(self):
"""
Returns the transpose of the matrix.
....
"""
return self.transpose()
T is not a conventional attribute that lives in a __dict__ or __slots__. In fact, you can see this immediately because the result of T changes if you modify the shape or contents of an array.
Since ndarray is a class written in C, it has special descriptors for the dynamic attributes it exposes. T is one of these dynamic attributes, defined as a PyGetSetDef structure. You can't override it by simple assignment, because there is nothing to assign to, but you can make a descriptor that overrides it at the class level.
As #hpaulj's answer suggests, the simplest solution may be to use a property to implement the descriptor protocol for you:
import numpy as np
class foo(np.ndarray):
#property
def T(self):
return self[8, :, :]
More complicated alternatives would be to make your own descriptor type, or even to extend the class in C and write your own PyGetSetDef structure. It all depends on what you are trying to achieve.
Following Mad Physicist and hpaulj's lead, the solution to my minimal working example is:
import numpy as np
class foo(np.ndarray):
def __new__(cls, input_array):
obj = np.asarray(input_array).view(cls)
return obj
#property
def T(self):
return 100.0
x = foo([1,2,3,4])
print("T is", x.T)
Which results in:
T is [1 2 3 4]
I have a class for a dynamical system, with methods for the ODE function and also the event function to terminate integration. I want to solve this with scipy.integrate.solve_ivp. According to the docs, this is done by assigning an attribute to your event function, as myEvent.terminal = True. However, since I have all my functions in an object, these are methods and not objects themselves, so I can't assign attributes. Any suggestions?
M(not)WE:
import numpy as np
from scipy.integrate import solve_ivp
class MySystem:
def __init__(self):
self.param_ = 1
def dynamics(self,t,x):
return (x-self.param)**3-x
def event(self, t, x):
return x
model = MySystem()
event1 = model.event
event1.terminal = True # this does not work
sol = solve_ivp(model.dynamics, [0, 100], [0, 10], events=event1)
Suppose you made two instances of MySystem:
model1 = MySystem()
model2 = MySystem()
If model1.event.terminal = True were allowed, then it would also affect
model2.event.terminal. Python disallows setting attributes on methods to
prevent this surprising action at a distance.
More on why this is disallowed is explained here.
Per PEP-0232 (my emphasis):
It is not possible to set
attributes on bound or unbound methods, except by doing so explicitly on the
underlying function object
It is possible to set attributes on the method using event1.__dict__['terminal'] = True
but note that doing so affects all instances of MySystem, not just the one instance, model.
Since this affects MySystem.event at the class level, it is better to set event.terminal in the class definition,
or by using MySystem.event.terminal = True immediately after the class is defined. (Note that MySystem.event is the underlying function object
referred to in the PEP quote above.)
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
class MySystem:
def __init__(self):
self.param = 1
def dynamics(self,t,x):
return (x-self.param)**3-x
def event(self, t, x):
return x
event.terminal = True
# MySystem.event.terminal = True # also works
model = MySystem()
event1 = model.event
# event1.__dict__['terminal'] = True # works, but perhaps confusing because it affects all instances
sol = solve_ivp(model.dynamics, t_span=(0, 1.5), y0=[1], events=event1)
print(sol)
plt.plot(sol['t'], sol['y'][0])
plt.scatter(sol['t_events'][0], [0], c='red')
plt.show()
It's not really clear what you want to achieve. But to give you some ideas:
1.you can try to make a wrapper for the function event, or make the function receive an object that can take an input as you like.
you can give the input you want to the model object and internally set it to the event, or create a function that gives it to the event once set to the model object.
Remove self from the event and add #staticmethod on top, this allows you to assign terminal to event1.
#staticmethod
def event(t, x):
return x
Thanks a lot, the scipy document is very unclear, this thread saved me. Here is how do in a bit different way. I define the event inside a member function that warps the ivp routine, where you can access the instance 'self' . Hope this will help someone.
def solve(self, y0, T, dy_dt):
def ivp_event(t, y):
E = self.get_energy(y)
return E - self.E_stop # E_stop is the target point
ivp_event.terminal = True
res = solve_ivp(
fun=dy_dt, t_span=(0, T), y0=y0,
events=ivp_event, **kw)
if not res.success:
raise Exception(res.message)
ys = res.y.T
return(res.t, ys, res.nfev)
In python, is it possible to chain together class methods and functions together? For example, if I want to instantiate a class object and call a method on it that affects an instance variable's state, could I do that? Here is an example:
class Test(object):
def __init__(self):
self.x = 'Hello'
#classmethod
def make_upper(y):
y.x = y.x.upper()
What I'm wanting to do is this:
h = Test().make_upper()
I want to instantiate a class object and affect the state of a variable in one line of code, but I would also like to be able to chain together multiple functions that can affect state or do something else on the object. Is this possible in python like it is in jQuery?
Yes, sure. Just return self from the instance methods you are interested in:
class Test(object):
def __init__(self):
self.x = 'Hello'
def make_upper(self):
self.x = self.x.upper()
return self
def make_lower(self):
self.x = self.x.lower()
return self
h = Test().make_upper()
print(h.x)
Output:
HELLO
Yes and no. The chaining certainly works, but h is the return value of make_upper(), not the object returned by Test(). You need to write this as two lines.
h = Test()
h.make_upper()
However, PEP-572 was recently accepted for inclusion in Python 3.8, which means someday you could write
(h := Test()).make_upper()
The return value of Test() is assigned to h in the current scope and used as the value of the := expression, which then invokes its make_upper method. I'm not sure I would recommend using := in this case, though; the currently required syntax is much more readable.
I'm struggling to understand why my simple code behaves like this. I create 2 instances a and b that takes in an array as argument. Then I define a method to change one of the instances array, but then both get changed. Any idea why this happen and how can I avoid the method changing the other instance?
import numpy as np
class Test:
def __init__(self, arg):
self.arg=arg
def change(self,i,j,new):
self.arg[i][j]=new
array=np.array([[11,12,13]])
a=Test(array)
b=Test(array)
#prints the same as expected
print(a.arg)
print(b.arg)
print()
a.change(0,0,3)
#still prints the same, even though I did
#not change b.arg
print(a.arg)
print(b.arg)
Because you assigned the same object as the instance members. You can use np.array(x, copy=True) or x.copy() to generate a new array object:
array = np.array([[11,12,13]])
a = Test(array.copy())
b = Test(np.array(array, copy=True))
Alternatively, if your arg is always a np.array, you could do it in the __init__ method (as noted by roganjosh in the comments):
class Test:
def __init__(self, arg):
self.arg = np.array(arg, copy=True)
...
Please guide to an explain of the difference between
object = class()
and
var = class method returning a class:
class Countsome(object):
#classmethod
def get(cls, x, y):
self = cls()
sum = self.add2(x, y)
print sum
return cls
def add2(self, x, y):
sum = x+y
return sum
xyz = Countsome.get(5, 9)
==========================================
class CountSome(object):
def __init__(self):
pass
def add2(self, x, y):
sum = x+y
print sum
xyz = CountSome()
xyz.add2(5, 9)
Looking to understand where I should use one, I am just printing the sum so not returning, so please assume I am asking this question for these kind of tasks(where returning results like sum is not important).
And looking for answers like, which one would be efficient, when.
What are the benefits of each and scenarios best suited for each. Guide to a source if possible
You kinda get it wrong. classmethod should be use when you need to perform action that doesn't need an instance but does need the cls object:
A class method receives the class as implicit first argument, just like an instance method receives the instance.
For example, if you have a COUNTER object in your class which counts how many instances were instantiated.
The second code is actually using staticmethod; that is a method defined in a class but don't need access to any class / instance attributes. staticmethod can be defined outside of a class but resides in it for convenience