I recently moved from Matlab to Python and want to transfer some Matlab code to Python. However an obstacle popped up.
In Matlab you can define a class with its methods and create nd-arrays of instances. The nice thing is that you can apply the class methods to the array of instances as long as the method is written so it can deal with the arrays. Now in Python I found that this is not possible: when applying a class method to a list of instances it will not find the class method. Below an example of how I would write the code:
class testclass():
def __init__(self, data):
self.data = data
def times5(self):
return testclass(self.data * 5)
classlist = [testclass(1), testclass(10), testclass(100)]
times5(classlist)
This will give an error on the times5(classlist) line. Now this is a simple example explaining what I want to do (the final class will have multiple numpy arrays as variables).
What is the best way to get this kind of functionality in Python? The reason I want to do this is because it allows batch operations and they make the class a lot more powerful. The only solution I can think of is to define a second class that has a list of instances of the first class as variables. The batch processing would need to be implemented in the second class then.
thanks!
UPDATE:
In your comment , I notice this sentence,
For example a function that takes the data of the first class in the list and substracts the data of all following classe.
This can be solved by reduce function.
class testclass():
def __init__(self, data):
self.data = data
def times5(self):
return testclass(self.data * 5)
from functools import reduce
classlist = [x.data for x in [testclass(1), testclass(10), testclass(100)]]
result = reduce(lambda x,y:x-y,classlist[1:],classlist[0])
print(result)
ORIGIN ANSWER:
In fact, what you need is List Comprehensions.
Please let me show you the code
class testclass():
def __init__(self, data):
self.data = data
def times5(self):
return testclass(self.data * 5)
classlist = [testclass(1), testclass(10), testclass(100)]
results = [x.times5() for x in classlist]
print(results)
Related
Apologizes for the clunky title. But I was wondering what the best practice was for the below example in terms of TDD and maintainability.
Take the class below.
class sampleClass():
def __init__(self, datframe):
self.dataframe = dataframe
self.other_dataframe = pandas.load_csv(....)
def modify_dataframe_method1(self):
self.dataframe = self.dataframe.join(self.other_dataframe)
def modify_dataframe_method2(self, df):
df = df.join(self.other_dataframe)
return df
Both of those methods can do the same thing, with just different syntax. If I created another method within the class, either of these statements would work end in the same result for self.dataframe.
def process(self):
self.modify_dataframe_method1()
def process(self):
self.dataframe = self.modify_dataframe_method2(self.dataframe)
Why are the pros and cons of each approach. While I am using a dataframe in the example, I can imagine doing similar things to jsons or other data structures.
Some times I found useful split bigger class in smaller classes with their methods and attributes that then I access assigning to an attribute of the bigger class an instance of the smaller class. In this way I can organize the class better: when I work using the console I can use nested dot notation instead of seeing a lot of attributes. For instance, I have an instrument with some parameters that can be grouped together and a method that is linked to these parameters. I would structure the class like this:
class params(object):
def __init__(self,P,I,D):
self.P = P
self.I = I
self.D = D
def compute_PID(self):
pass
class instrument(object):
def __init__(self,name,SN,P,I,D):
self.name = name
self.SN = SN
self.params = params(P,I,D)
def swith_on(self):
pass
myinstrument = instrument('blender','123',45,4,3)
myinstrument.params.P
Is there any drawback of this deign patter? I imagine that from the point of view of the memory it requires more memory, but working with the dot notation make the things easier compared to a dictionary.
Consider the following situation:
class A:
def __init__(self):
self.b_list = []
def add_element(b)
self.b_list.append(b)
class B:
def __init__(self,x):
self.x = x
class C:
def __init__(self,a,other_data):
self.a = a
def find_new_b(self):
....
def solve(c):
return c.find_new_b()
Each instance of class A has a list of instances of class B, that are added in an incremental way.
I need to iterate over all the instances of class A and find for each of them a new element of class B.
I'm using multiprocessing to do that
list_of_c_elements = [...]
pool = multiprocessing.Pool()
results = pool.map(solve, list_of_c_elements)
The problem
In results I have a list of results and I would like to understand of which instance of class A the new instance of class B belongs. Each instance of class B is generic, and I would like to keep the two classes decoupled.
Considered solution
Change solve() to:
def solve(c):
return (c.a, c.find_new_b())
I have to compare all the elements of class A I have with the one returned (very inefficient).
I cannot do something like:
for output in results:
output[0].add_element(output[1])
since the instance of class A returned is another instance.
Is there a more efficient way to achieve my goal?
C could additionally hold id(a) in a member and you can generate an index dictionary {id(a): a} if necessary. Be aware that all calls of id() must of course happen in the main process to produce usable results.
I have a class that wraps around python deque from collections. When I go and create a deque x=deque(), and I want to reference the first variable....
In[78]: x[0]
Out[78]: 0
My question is how can use the [] for referencing in the following example wrapper
class deque_wrapper:
def __init__(self):
self.data_structure = deque()
def newCustomAddon(x):
return len(self.data_structure)
def __repr__(self):
return repr(self.data_structure)
Ie, continuing from above example:
In[75]: x[0]
Out[76]: TypeError: 'deque_wrapper' object does not support indexing
I want to customize my own referencing, is that possible?
You want to implement the __getitem__ method:
class DequeWrapper:
def __init__(self):
self.data_structure = deque()
def newCustomAddon(x):
return len(self.data_structure)
def __repr__(self):
return repr(self.data_structure)
def __getitem__(self, index):
# etc
Whenever you do my_obj[x], Python will actually call my_obj.__getitem__(x).
You may also want to consider implementing the __setitem__ method, if applicable. (When you write my_obj[x] = y, Python will actually run my_obj.__setitem__(x, y).
The documentation on Python data models will contain more information on which methods you need to implement in order to make custom data structures in Python.
I have a class whose members are lists of numbers built by accumulating values from experimental data, like
class MyClass:
def __init__(self):
container1 = []
container2 = []
...
def accumulate_from_dataset(self,dataset):
for entry in dataset:
container1.append( foo (entry) )
container2.append( bar (entry) )
...
def process_accumulated_data(self):
'''called when all the data is gathered
'''
process1(container1)
process2(container2)
...
Issue: it would be beneficial if I could convert all the lists into numpy arrays.
what I tried: the simple conversion
self.container1 = np.array(self.container1)
works. Although, if I would like to consider "more fields in one shot", like
lists_to_convert = [self.container1, self.container2, ...]
def converter(lists_to_convert):
for list in lists_to_convert:
list = np.array(list)
there is not any effective change since the references to the class members are passed by value.
I am thus wondering if there is a smart approach/workaround to handle the whole conversion process.
Any help appreciated
From The Pragmatic Programmer:
Ask yourself: "Does it have to be done this way? Does it have to be done at all?
Maybe you should rethink your data structure? Maybe some dictionary or a simple list of lists would be easier to handle?
Note that in the example presented, container1 and container2 are just transformations on the initial dataset. It looks like a good place for list comprehension:
foo_data = [foo(d) for d in dataset]
# or even
foo_data = map(foo, dataset)
# or generator version
foo_data_iter = (foo(d) for d in dataset)
If you really want to operate on the instance variables as in the example, have a look at getattr and hasattr built-in functions
There isn't an easy way to do this because as you say python passes "by-reference-by-value"
You could add a to_numpy method in your class:
class MyClass:
def __init__(self):
container1 = []
container2 = []
...
def to_numpy(self,container):
list = self.__getattr__(container)
self.__setattr__(container,np.array(list))
...
And then do something like:
object = MyClass()
lists_to_convert = ["container1", "container2" ...]
def converter(lists_to_convert):
for list in lists_to_convert:
object.to_numpy(list)
But it's not very pretty and this sort of code would normally make me take a step back and think about my design.