Python Deque Array adding to array crashes python - python

I am working on a double ended queue in python and everything seems to be working fine except for my preappend(adding to the front) method. When I call upon this method in main it crashes python and I am super confused as to why, here is my code:
import ctypes
class dequeArray:
def __init__(self):
"""Create an empty Array """
self._capacity = 4
self._data = self.makeArray(self._capacity)
self._dataSize = 0
self._front = 0
def makeArray(self, capacity):
capacity = self._capacity
return (self._capacity * ctypes.py_object)()
def isEmpty(self):
return self._dataSize == 0
def __len__(self):
return self._dataSize
def _userIndex2BlockIndex(self, userIndex):
return (self._front + userIndex)% self._capacity
def __getitem__(self, userIndex):
return self._data[userIndex]
def __setitem__(self, userIndex, value):
self._data[self._front(userIndex)] = value
def preappend(self, item):
if self._dataSize == 0:
self._data[self._front] = item
self._dataSize += 1
elif self._dataSize != self._capacity:
for e in range(self._dataSize-1,0,-1):
self._data[e] = self._data[e-1]
self._data[self._front] = item
self._dataSize += 1
else:
for e in range(self._capacity-1,0,-1):
self._data[e] = self._data[e-1]
self._data[self._front] = item
in main I create an empty deque
d = dequeArray()
then test len(d) and that works fine but when I do
d.preappend(2)
it crashes python... Please help

In the general, deques() never crash when used with normal Python objects.
With ctypes, all bets are off because C calls by pass all the invariant checks, type safety checks, pointer/index range checks etc.
Deques only access limited features for an object created with ctypes. At a minimum, it needs to support reference counting. To display, it needs a repr. To remove() or index(), it needs to support eq().

Related

class self acts like integer

I didn't understand why. And It will raise an error 'int' object has no attribute 'v', but I want to access the self.v. When I print only self it will print some numbers. I couldn't understand what was going on. Here is my code.
class Candidate:
def __init__(self,val,pscore,nscore):
self.v = val
self.p = pscore
self.n = nscore
def __str__(self):
return f"{self.v} ({self.p},{self.n})"
def check_plus_pos(self, guessval):
count = 0
b = self.v
a = str(b)
guessval = str(guessval)
for i in range(0,len(a)):
if a[i] == guessval[i]:
count += 1
return count
def check_neg_pos(self, guessval):
count = 0
b = self.v
a = str(b)
guessval = str(guessval)
for i in range(0,len(a)):
for j in range(0,len(guessval)):
if a[i] == guessval[j] and a[i] != guessval[i]:
count += 1
return count
def consistent(self, guess):
if Candidate.check_plus_pos(self,guess.v) == guess.p and Candidate.check_neg_pos(self,guess.v) == guess.n:
return True
else:
return False
The problem occurs at b == self.v I wanted to assign the self.v value to a variable.
To be honest it's pretty hard to understand what that code/class is supposed to do, imho it needs some serious refactoring.
My guess is you should:
instantiate your class somewhere
use the method as an instance method, so invoke it with self and not the class name
do NOT pass self explicitly at all
do NOT use abbreviations which are not commonly known
do NOT use single letter variables a means literally nothing
use docstrings for non-trivial functions (or as a rule of thumb to most of functions/methods)
use type hints, which will help you catch this kind of errors automatically (if you configure your IDE that is)
get rid of the assignment to b at all, it's not reused and doesn't seem do anything. This will do the same a = str(self.v)
... # all the class related code above
def check_neg_pos(self, guessval):
count = 0
a = str(self.v)
guessval = str(guessval)
for i in range(0,len(a)):
for j in range(0,len(guessval)):
if a[i] == guessval[j] and a[i] != guessval[i]:
count += 1
return count
def is_consistent(self, guess: Candidate)->bool:
return bool(self.check_plus_pos(guess.v) == guess.p and self.check_neg_pos(guess.v) == guess.n)
# Example usage
candidate_1 = Candidate(1,2,3)
candidate_2 = Candidate(4,5,6)
candidates_consistent = candidate_1.is_consistent(guess=candidate_2)
print(candidates_consistent)

Sharing resources between two classes

I have provided a working example where I have a dynamic array implemented as custom type in Python 3. I wish to use a single instance of this dynamic array as a common resource for implementing, say, N stacks. How do I do that?
I imagine I would like to give each stack an access to only a certain part of the DynamicArray by making demarcation points _start and _end. In order to have _start and _end for each stack, I would like to wrap them in a helper class _StackRecord. In case I am successful in providing a modifiable view of DynamicArray, I want _StackRecord to do all the heavy lifting of poping and pushing such that the stacks don't collide while the underlying DynamicArray expands/shrinks as per the need. I know I am asking for too much, but I might learn some useless skills while I fail to do this.
Any suggestions/criticism towards modularity, maintainability and good practices are wholeheartedly welcome.
import ctypes
class DynamicArray:
"""Expandable array class similar to Python list"""
def __init__(self, size=0):
self._n = size
self._capacity = size + 1
self._A = self._make_low_level_array(self._capacity)
def _make_low_level_array(self, capacity):
return (capacity*ctypes.py_object)()
# following two methods are needed for Python to implement __iter__
def __len__(self):
return self._n
def __getitem__(self, index_key):
if isinstance(index_key, slice):
start, stop, step = index_key.indices(len(self))
return [self._A[i] for i in range(start, stop, step)]
elif isinstance(index_key, int):
if 0 <= index_key < self._n :
return self._A[index_key]
else:
raise IndexError("index out of bounds")
elif isinstance(index_key, tuple):
raise NotImplementedError('Tuple as index')
else:
raise TypeError('Invalid argument type: {}'.format(type(key)))
def __setitem__(self, index_k, value):
if 0 <= index_k < self._n :
self._A[index_k] = value
else:
raise IndexError("index out of bounds")
###################################################################
class FixedMultiStack:
class _StackRecord(DynamicArray):
def __init__(self, array: DynamicArray, stack_number=0, size_of_each=10):
self._stack = stack_number
self._start = stack_number*size_of_each
self._end = self._start + size_of_each
# try commenting the following lines
self._n = size_of_each
self._A = DynamicArray(self._n)
# If I have to use self._A then I would like it to point
# to array[self._start:self._end]
for i in range(self._start, self._end):
array[i] = i
for i in range(self._n):
self._A[i] = array[self._start+ i]
def __init__(self, numStack=1, sizeEach=10):
self._stacks = []
self._items = DynamicArray(numStack*sizeEach)
for i in range(numStack):
self._stacks.append(self._StackRecord(self._items, i, sizeEach))
def __getitem__(self, stack_number):
return self._stacks[stack_number]
if __name__ == "__main__":
fms = FixedMultiStack(3,10)
print(list(fms[0]))
print(list(fms[1]))
print(list(fms[2]))
print(list(fms._items))
Issues
I am doing the wasteful act of making a local copy called self._A. How do I avoid that? Why can't I just work on the global dynamic array passed to my local record keeper _StackRecord?
What do I expect?
fms = FixedMultiStack(3,10), A fixed multi stack packing 3 stacks of size 10 each such that
I would like, if self._A is necessary, the local self._A to refer to that part of DynamicArray which corresponds to the given stack number.
So that print(list(fms[n])) gives me the contents of nth stack
While print(list(fms._items)) should give me the combine state of all the stacks. Yikes! print(list(fms._items)) is ugly. How about print(list(fms))?
I should be able to write something like self._items[n].push(val), self._items[n].pop() to push and pop on n-th stack.
You can use memoryview for creating the different views over the entire array:
class FixedMultiStack:
def __init__(self, m, n):
self.data = bytearray(m*n)
view = memoryview(self.data)
self.stacks = [view[i*n:(i+1)*n] for i in range(m)]
def __getitem__(self, index):
return self.stacks[index]

Sometimes None is printed - and sometimes it doesn't, can't get why?

I got this school assignment, here is my code:
class Doubly_linked_node():
def __init__(self, val):
self.value = val
self.next = None
self.prev = None
def __repr__(self):
return str(self.value)
class Deque():
def __init__(self):
self.header = Doubly_linked_node(None)
self.tailer = self.header
self.length = 0
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (index.next is None):
string+=" " + str(index.next.value)
index = index.next
return string
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
self.header.prev=new
self.header=new
self.length+=1
if self.tailer.value==None:
self.tailer = self.header
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
self.tailer.next=new
self.tailer=new
self.length+=1
if self.header.value==None:
self.header = self.tailer
it builds a stack, allowing you to add and remove items from the head or tail (I didn't include all the code only the important stuff).
When I initiate an object, if I return self.next it prints None, but if I return self.prev, it prints nothing, just skips, I don't understand why since they are both defined exactly the same as you see, and if I insert only head several times for example for i in range(1,5): D.head_insert(i) and then I print D it prints 5 4 3 2 1 None but if I do tail insert for example for i in range(1,5): D.tail_insert(i) and print D it prints 1 2 3 4 5"as it should without the None. Why is that?
I have included an image:
Keep in mind that you create a Deque which is not empty. You're initializing it with a Node with value None
You're interchanging the value and the Node object. When you're checking if self.tailer.value==None: it's probably not what you're meaning
Following to point 2 is a special handling for the empty Deque, where header and tailer is None
Here is what I have in mind, if I would implement the Deque. I'm slightly changed the return value of __repr__.
class Deque():
def __init__(self):
self.header = None
self.tailer = None
self.length = 0
def __repr__(self):
if self.header is None:
return 'Deque<>'
string = str(self.header.value)
index = self.header.next
while index!=None:
string+=" " + str(index.value)
index = index.next
return 'Deque<'+string+'>'
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
if self.length==0:
self.tailer=new
else:
self.header.prev=new
self.header=new
self.length+=1
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
if self.length==0:
self.header=new
else:
self.tailer.next=new
self.tailer=new
self.length+=1
Following Günthers advice, I have modified the __repr__ to this:
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (str(index.next) == "None"):
string += (" " + str(index.next.value))
index = index.next
return string
that did solve the problem, but it is the ugliest solution I have ever seen.
does anyone know a better way?
Following to the question of a better __repr__ method here my proposal. Extend the Deque class with an __iter__ method. So you can iterate over the Deque which is nice to have, e.g.:
for item in D:
print item
Based on that the __repr__ method is easy. Here is the whole change:
def __repr__(self):
return 'Deque<'+' '.join([str(item.value) for item in self])+'>'
def __iter__(self):
index=self.header
while index is not None:
yield index.value
index=index.next

Python Printing a Deque

I have an entire Deque Array class that looks like this:
from collections import deque
import ctypes
class dequeArray:
DEFAULT_CAPACITY = 10 #moderate capacity for all new queues
def __init__(self):
self.capacity = 5
capacity = self.capacity
self._data = self._make_array(self.capacity)
self._size = 0
self._front = 0
def __len__(self):
return self._size
def __getitem__(self, k): #Return element at index k
if not 0 <= k < self._size:
raise IndexError('invalid index')
return self._data[k]
def isEmpty(self):
if self._data == 0:
return False
else:
return True
def append(self, item): #add an element to the back of the queue
if self._size == self.capacity:
self._data.pop(0)
else:
avail = (self._front + self._size) % len(self._data)
self._data[avail] = item
self._size += 1
#def _resize(self, c):
#B = self._make_array(c)
#for k in range(self._size):
#B[k] = self._A[k]
#self._data = B
#self.capacity = capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
def removeFirst(self):
if self._size == self.capacity:
self._data.pop(0)
else:
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
print(answer)
def removeLast(self):
return self._data.popleft()
def __str__(self):
return str(self._data)
and when I try to print the deque in the main it prints out something like this,
<bound method dequeArray.__str__ of <__main__.dequeArray object at 0x1053aec88>>
when it should be printing the entire array. I think i need to use the str function and i tried adding
def __str__(self):
return str(self._data)
and that failed to give me the output. I also tried just
def __str__(self):
return str(d)
d being the deque array but I still am not having any success. How do I do i get it to print correctly?
you should call the str function of each element of the array that is not NULL, can be done with the following str function:
def __str__(self):
contents = ", ".join(map(str, self._data[:self._size]))
return "dequeArray[{}]".format(contents)
What I get when I try to q = dequeArray(); print(q) is <__main__.py_object_Array_5 object at 0x006188A0> which makes sense. If you want it list-like, use something like this (print uses __str__ method implicitly):
def __str__(self):
values = []
for i in range(5):
try:
values.append(self._data[i])
except ValueError: # since accessing ctypes array by index
# prior to assignment to this index raises
# the exception
values.append('NULL (never used)')
return repr(values)
Also, several things about the code:
from collections import deque
This import is never user and should be removed.
DEFAULT_CAPACITY = 10
is never used. Consider using it in the __init__:
def __init__(self, capacity=None):
self.capacity = capacity or self.DEFAULT_CAPACITY
This variable inside __init__ is never user and should be removed:
capacity = self.capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
Though this is a valid code, you're doing it wrong unless you're absolutely required to do it in your assignment. Ctypes shouldn't be used like this, Python is a language with automated memory management. Just return [] would be fine. And yes, variable c is never used and should be removed from the signature.
if self._data == 0
In isEmpty always evaluates to False because you're comparing ctypes object with zero, and ctypes object is definitely not a zero.

Linked queue in python can't tell if it's empty

So I built a linked queue class in python that looks like this.
class queue:
class _Node:
def __init__(self, elem, next):
self._elem = elem
self._next = next
def __init__(self):
self._rear = None
self._front = None
self._size = 0
def enqueue(self, value):
if self.isEmpty:
self._front = self._Node(value, None)
self._rear = self._front
self._size += 1
return
self._rear._next = self._Node(value, None)
self._rear = self._rear._next
self._size += 1
return
def dequeue(self):
retVal = self._front._elem
self._front = self._front._next
self._size -= 1
if self.isEmpty:
self._rear = None
return retVal
def __len__(self):
return self._size
def isEmpty():
return len(self) == 0
I'm using this class in order to create a really basic print queue that feeds into two printers. My problem is, my isEmpty function in the class seems to think that it is always empty. If I add 3 print jobs, then try to display them, it will only display the last one because the enqueue function thinks that the queue is empty. I just can't seem to figure out why so any help would be much appreciated.
The problem you are actually encountering is that you are not calling the method, but just referring to the boolean value of the method object itself, which is always true. It should be:
if self.isEmpty():

Categories