Python: Numpy Array : cant access/reference to a numpy array from another class - python

I have a data acquisation class that takes data and saves it into a numpy array.
voltage = float((data.decode())[0:-2]) * 1000
print(voltage)
self.xxList = np.append(self.xxList, [voltage])
Those lines are in a while loop which is managed by a thread. I return the "self.xxlist" with a simple getter:
def get_xlist(self):
return self.xxList
Then i try to have a reference to the same list in another class, which of course has the instance of my data acquistion class.
self.mySerial = SerialFirat(self)
self.xaList = self.mySerial.get_xlist()
This doesn't work with numpy - The self.xaList always stays the same (empty) and doesnt update on any acquired data - but works with a regular python list which uses simple .append(data).
I guess this might be due the way an element is appended to a numpy array, which creates a new list and returns the reference to it, each time an element is appended. The list that i referenced is the first list and the newly created lists have some different adress so the referenced list always stays the same.
I couldnt find a work around to make it function like a normal python list. I would appriciate any help and a clarification if my conclusion on why it doesnt work is correct.
PS: I use the data to plot a live graph but the list - xaList - i feed to the plotting function is always empty and nothings is being plotted. If i directly feed the xxList (the List i write the serialData in) it works but that really leads to a crappy object oriented design

Related

I set 3 arrays to the same thing, changing a single entry in one of them also changes the other two arrays. How can I make the three arrays separate?

I am making a puzzle game in a command terminal. I have three arrays for the level, originlevel, which is the unaltered level that the game will return to if you restart the level. Emptylevel is the level without the player. Level is just the level. I need all 3, because I will be changing the space around the player.
def Player(matrix,width):
originlevel = matrix
emptylevel = matrix
emptylevel[PlayerPositionFind(matrix)]="#"
level = matrix
The expected result is that it would set one entry to "#" in the emptylevel array, but it actually sets all 3 arrays to the same thing! My theory is that the arrays are somehow linked because they are originally said to the same thing, but this ruins my code entirely! How can I make the arrays separate, so changing one would not change the other?
I should not that matrix is an array, it is not an actual matrix.
I tried a function which would take the array matrix, and then just return it, thinking that this layer would unlink the arrays. It did not. (I called the function IHATEPYTHON).
I've also read that setting them to the same array is supposed to do this, but I didn't actually find an answer how to make them NOT do that. Do I make a function which is just something like
for i in range(0,len(array)):
newarray.append(array[i])
return newarray
I feel like that would solve the issue but that's so stupid, can I not do it in another way?
This issue is caused by the way variables work in Python. If you want more background on why this is happening, you should look up 'pass by value versus pass by reference'.
In order for each of these arrays to be independent, you need to create a copy each time you assign it. The easiest way to do that is to use an array slice. This means you will get a new copy of the array each time.
def Player(matrix,width):
originlevel = matrix[:]
emptylevel = matrix[:]
emptylevel[PlayerPositionFind(matrix)]="#"
level = matrix[:]

Python shallow copy and deep copy in using append method

Some problems come out when using append method in python3.5. The code is presented
# generate boson basis in lexicographic order
def boson_basis(L,N):
basis=[]
state=[0 for i in range(1,L+1)]
pos=0
# initialize the state to |N,0,...,0>
state[0]=N
basis.append(state)
# find the first non-zero position in reverse order
while state[L-1]<N:
for i in range(-2,-L-1,-1):
if state[i]>0:
pos=L+i
break
sum=0
for i in range(0,pos):
sum=sum+state[i]
state[pos]=state[pos]-1
state[pos+1]=N-sum-state[pos]
basis.append(state)
return basis
result=boson_basis(3,3)
the expected result should be [[3,0,0],[2,1,0],...,[0,0,3]], but this code generates wrong results with all elements are the same as the last one, i.e. [[0,0,3],...,[0,0,3]]. I use the pdb to debug it and I find that once the state is modified, the former state that has been appended into basis is also changed simultaneously. It implies that append uses deepcopy automatically which is beyond my understanding. In fact, this error can be fixed if we use basis(state.copy()) explicitly.
On the other hand, the following simple code shows no error in using append
x=3
b=[]
b.append(x)
x=x+2
after x is changed to x=5, b remains unchanged b=[3]. It really puzzles me and seems contradictory with the former example.
As revealed in the comments already, there's no copy whatsoever involved in an append operation.
So you'll have to explicitly take care of this yourself, e.g. by replacing
basis.append(state)
with
basis.append(state[:])
The slicing operation with : creates a copy of state.
Mind: it does not copy the lists elements - which as long as you're keeping only plain numbers and not objects in your list should be fine though.

How to define a callable function whenever the value of any element in the list gets changed?

I know this question is kind of simple and silly but I got stymied of searching the internet. Consider we have a 2-dimensional list in Python which represents a game board of hex and its elements would be changed by some function (like playing stone at some cell in the game board).
What I am looking for is a tool in Python that could define a function to be called whenever the value of any element in the array gets changed.
I already found the function trace in tkinter which calls a function when StringVar,DoubleVar and so on get changed.
I was wondering if a similar one could be found for simple lists or even numpy lists.
Your requirements:
2-dimensinal list in python which represents a game board of hex
and its elements would be changed by some function (like playing stone at some cell in the game board).
a function to be called whenever the value of any element in the array gets changed.
The straight forward way to implement this is to define a class representing the board and actions. It will contain the 2d list (could be numpy array, but that may not be necessary).
It would also define methods that change the list, and perform the recording/callback.
class Board():
def __init__(...)
self.list2d=[] # 2d nested list
def record_play(...):
<action when a cell is changed>
def play(...):
<change self.list2d>
self.record_play(...)
As long a the Board object controls all the changes, you don't need a more generic tracking tool, or even a subclass of list or array (though those are possible). Just make sure you call the tracking function each time you call the change function.
If you were doing this across different classes and kinds of objects it could be worth while constructing something more abstract. But for a one-off case, just do the obvious.

Passing subset reference of array/list as an argument in Python

I'm kind of new (1 day) to Python so maybe my question is stupid. I've already looked here but I can't find my answer.
I need to modify the content of an array at a random offset with a random size.
I have a Python API to interface a DDL for an USB device which I can't modify. There is a function just like this one :
def read_device(in_array):
# The DLL accesses the USB device, reads it into in_array of type array('B')
# in_array can be an int (the function will create an array with the int
# size and return it), or can be an array or, can be a tuple (array, int)
In MY code, I create an array of, let's say, 64 bytes and I want to read 16 bytes starting from the 32rd byte. In C, I'd give &my_64_array[31] to the read_device function.
In python, if a give :
read_device(my_64_array[31:31+16])
it seems that in_array is a reference to a copy of the given subset, therefore my_64_array is not modified.
What can I do ? Do I have to split my_64_array and recombine it after ??
Seeing as how you are not able to update and/or change the API code. The best method is to pass the function a small temporary array that you then assign to your existing 64 byte array after the function call.
So that would be something like the following, not knowing the exact specifics of your API call.
the_64_array[31:31+16] = read_device(16)
It's precisely as you say, if you input a slice into a function it creates a reference copy of the slice.
Two possible methods to add it later (assuming read_device returns the relevant slice):
my_64_array = my_64_array[:32] + read_device(my_64_array[31:31+16]) + my_64_array[31+16:]
# equivalently, but around 33% faster for even small arrays (length 10), 3 times faster for (length 50)...
my_64_array[31:31+16] = read_device(my_64_array[31:31+16])
So I think you should be using the latter.
.
If it was a modifiable function (but it's not in this case!) you could be to change your functions arguments (one is the entire array):
def read_device(the_64_array, start=31, end=47):
# some code
the_64_array[start:end] = ... #modifies `in_array` in place
and call read_device(my_64_array) or read(my_64_array, 31, 31+16).
When reading a list subset you're calling __getitem__ with a slice(x, y) argument of that list. In your case these statements are equal:
my_64_array[31:31+16]
my_64_array.__getitem__(slice(31, 31+16))
This means that the __getitem__ function can be overridden in a subclass to obtain different behaviour.
You can also set the same subset using a[1:3] = [1,2,3] in which case it'd call a.__setitem__(slice(1, 3), [1,2,3])
So I'd suggest either of these:
pass the list (my_64_array) and a slice object to read_device instead of passing the result of __getitem__, after which you could read the necessary data and set the corresponding offsets. No subclassing. This is probably the best solution in terms of readability and ease of development.
subclassing list, overriding __getitem__ and __setitem__ to return instances of that subclass with a parent reference, and then change all modifying or reading methods of a list to reference a parent list instead. This might be a little tricky if you're new to python, but basically, you'd exploit that python list properties are largely defined by the methods inside a list instance. This is probably better in terms of performance as you can create references.
If read_device returns the resulting list, and that list is of equal size, you can do this: a[x:y] = read_device(a[x:y])

Appending instances of an object to a list only works with time consuming deepcopy, how can I change this?

I have a pymzml.run.Reader class from the pymzml package. This is a generator object, when looping through it it yields instances of the Spectrum class (also from the pymzml package). I'm comparing different instances with each other. Because pymzml.run.Reader is a generator object, after looping through them they can't be used anymore, so I save them in a list for comparison later on.
However, when I save them in a list and then loop through the list printing the id's of the spectra, it shows that it only save the last spectrum. To clarify:
import pymzml
def test(msrun):
for spectrum in msrun:
print spectrum['id']
spectrumList.append(spectrum)
print '-'*20
for i in spectrumList:
print i['id']
msrun = pymzml.run.Reader(r'JG_Ti02-C1-1_C2-01A_file1.aligned.mzML')
gives:
1
2
3
4
5
--------------------
5
5
5
5
5
The pymzml has a deRef() function that makes a deepcopy of the spectrum, so the following does work correctly:
import pymzml
def test(msrun):
for spectrum in msrun:
print spectrum['id']
spectrumList.append(spectrum.deRef())
msrun = pymzml.run.Reader(r'JG_Ti02-C1-1_C2-01A_file1.aligned.mzML')
However, making deepcopies is a major bottleneck which I'm trying to get out of my application. How can I append the spectrum instances to a list so that not only the last spectrum is appended multiple times?
It can't be just saving the last spectrum -- you're doing all the right things to save each object to the list.
The problem is you're getting the same object over and over.
Printing id(spectrum) in the loop to get its memory address will show that it is one object repeated with its id and other attributes changed.
While you don't necessarily need copy.deepcopy(), you do need to make a copy. Try copy.copy(), and look at the source of Spectrum.decRef() to see how it does its copying.
Most likely, you do need to decRef() each one to make them independent -- otherwise, why would the class provide a special method?

Categories

Resources