Sharing resources between two classes - python

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]

Related

Objects passing objects

I'm new to python and am currently trying to use an old module to output graphs. The code below is a excerpt from the module that uses rpy to design
standard celeration charts (don't look it up).
I'm having trouble understanding how the class Element and class Vector work together.
I've been trying to pass the a element object to the vector get_elements but I'm not sure if that's what I should be doing.
Any help would be appreciated. Thanks!
class Element(object):
"""Base class for Chartshare vector elements."""
def __init__(self, offset=0, value=0):
self.offset=offset
self.value=value
self.text=''
def setText(self, value):
self.value=value
def getText(self):
return self.value
text = property(getText, setText)
class Vector(object):
"""Base class for Chartshare Vectors."""
def __init__(self, name='', color='black', linetype='o', symbol=1, clutter=0, start=0, end=140, continuous=False, debug=False):
self.name=name
self.color=color
self.linetype=linetype
self.symbol=symbol
self.start=start
self.end=end
self.elements={}
self.debug=debug
self.continuous=continuous
if not self.continuous:
for i in range(self.start, self.end+1):
self.elements[i]='NaN'
def getSymbol(self):
return self._symbol
def setSymbol(self, value):
if (type(value) == int):
if (value >= 0) and (value <= 18):
self._symbol = value
else:
raise SymbolOutOfRange, "Symbol should be an integer between 0 and 18."
elif (type(value) == str):
try:
self._symbol = value[0]
except IndexError:
self._symbol=1
else:
self._symbol = 1
symbol = property(getSymbol, setSymbol)
def getLinetype(self):
return self._linetype
def setLinetype(self, value):
if (value == 'p') or (value == 'o') or (value == 'l'):
self._linetype = value
else:
raise InvalidLinetype, "Line type should be 'o', 'p', or 'l'"
linetype = property(getLinetype, setLinetype)
def get_elements(self):
"""Returns a list with the elements of a Vector."""
retval = []
for i in range(self.start, self.end+1):
if (not self.continuous):
retval.append(self.elements[i])
else:
if (self.elements[i] != 'NaN'):
retval.append(self.elements[i])
return retval
def get_offsets(self):
"""Returns a list of the offsets of a Vector."""
retval = []
for i in range(self.start, self.end+1):
if (not self.continuous):
retval.append(i)
else:
if (self.elements[i] == 'NaN'):
retval.append(i)
return retval
def to_xml(self, container=False):
"""Returns an xml representation of the Vector."""
if (container == False):
container = StringIO.StringIO()
xml = XMLGenerator(container)
attrs = {}
attrs[u'name'] = u"%s" % self.name
attrs[u'symbol'] = u"%s" % self.symbol
attrs[u'linetype'] = u"%s" % self.linetype
attrs[u'color'] = u"%s" % self.color
xml.startElement(u'vector', attrs)
for i in range(self.start, self.end+1):
if (self.elements[i] != 'NaN'):
attrs.clear()
attrs[u'offset'] = u"%s" % i
xml.startElement(u'element', attrs)
xml.characters(u"%s" % self.elements[i])
xml.endElement(u'element')
xml.endElement(u'vector')
def render(self):
"""Plots the current vector."""
if (self.debug):
print "Rendering Vector: %s" % self.name
print self.elements
r.points(x=range(self.start, self.end+1),
y=self.elements,
col=self.color,
type=self.linetype,
pch=self.symbol)
if (self.debug):
print "Finished rendering Vector: %s" % self.name
Vector's get_elements() doesn't take any arguments. Well, technically it does. It takes self. self is syntactic sugar that lets you do this:
vec = Vector()
vec.get_elements()
It's equivalent to this:
vec = Vector()
Vector.get_elements(vec)
Since get_elements() doesn't take any arguments, you can't pass a to it. Skimming the code, I don't see a set_elements() analog. This means you'll have to modify the vector's element's dictionary directly.
vec = Vector()
vec.elements[a] = ...
print(vec.get_elements()) # >>> [a,...]
As I can see, there is no place in this code where you are assigning self.elements with any input from a function. You are only initialising it or obtaining values
Also note that the .get_elements() function doesn't have any arguments (only self, that is the object where you are calling it in), so of course it won't work.
Unless you can do something such as the following, we would need more code to understand how to manipulate and connect these two objects.
element_obj = Element()
vector_obj = Vector()
position = 4
vector_obj.elements[4] = element_obj
I got to this answer with the following: as I can see, the elements property in the Vector class is a dictonary, that when you call vector_obj.get_elements() is casted to an array using the start and end parameters as delimiters.
Unless there is something else missing, this would be the only way I could think out of adding the an element into a vector object. Otheriwse, we would need some more code or context to understand how these classes behave with each other!
Hope it helps!

How can I create my own list iterable without even using subclass?

I am learning Python and have developed few web applications etc. Now, I want to dig deeper and learn about the under the hood workings of Python. For that, I would like to make my own list iterable. Here is my effort so far:
class CustomList:
def __init__(self,*args):
self.nums=args
self.count=0
i=0
for arg in args:
i+=1
self.total=i
def __iter__(self):
return self
def __next__(self):
if self.count >= self.total:
raise StopIteration
self.count+=1
mylist=CustomList(1,2,3,4)
for item in mylist:
print(item)
Now, in my next function, I am unsure how to iterate through my self.nums so that my print(item) prints each item in the self.nums one by one.
I don't really want to use anything related to len(), append() etc. I want to create them on my own. So that's the future plan. For now, I can't even iterate through the user given *args.
You need to go back another level. args in your MyList(*args) is already an iterable.
Each list item needs to explicitly point to the next one. So each list item needs a record of the next pointer and the data associated with it. This could be a dict but then MyList.append would need to explicitly access the records. For me the MyListItem class is clearer.
class MyListItem:
def __init__(self, data):
self.next = None
self.data = data
def link_to(self, child):
self.next = child
The MyList class can then use this as the nodes in it's list structure. There may be better implementations but this is the most basic I can get to.
class MyList:
def __init__(self):
""" Create the list header record, initialised to an empty list. """
self.top = None
self.bottom = None
self.curr = None # Used to iterate through the list.
def append(self, data):
node = MyListItem(data) # Create the List item
if self.top is None: # If the list is empty point top to node
self.top = node
else:
self.bottom.link_to(node) # Otherwise point the bottom node to the new node
self.bottom = node # Point the bottom to the new node
def __iter__(self):
self.curr = self.top # Initialise the current pointer to top
return self
def __next__(self):
if self.curr: # If the curr pointer is not None
res = self.curr.data # Get the data
self.curr = self.curr.next # Set curr to next
return res # Return the data
else:
raise StopIteration
Test it
test = MyList()
test.append(1)
test.append('Two')
test.append([1, 2, 3])
for node in test:
print(node)
1
Two
[1, 2, 3]

Python Deque Array adding to array crashes 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().

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.

Python: Array Implementation of a Binary Search Tree

I've seen many types of linked-list implementations of binary search trees, and I am wondering how I would go about implementing one in an array. Is this possible? And how would it look like if it is?
Thank you so much!
Here is an array implementation of a queue!
class Queue:
MAX = 6
def __init__(self):
self.queue = [None for x in range(self.MAX)]
self.front = 0
self.rear = 0
def isEmpty(self):
return self.front == self.rear
def size(self):
if self.isEmpty():
return 0
elif self.front < self.rear:
return self.rear - self.front
else:
return self.rear + self.MAX - self.front
def isFull(self):
return self.size() == self.MAX - 1
def insert(self, data):
if self.isFull():
print("Cannot insert to full queue")
else:
self.queue[self.rear] = data
self.rear = (self.rear + 1) % self.MAX
return data
def delete(self):
if self.isEmpty():
print("Cannot delete from empty queue")
else:
data = self.queue[self.front]
self.queue[self.front] = None
self.front = (self.front + 1) % self.MAX
return data
def peek(self):
if self.isEmpty():
return None
else:
return self.queue[self.front]
def display(self):
if self.isEmpty():
print("Empty Queue")
elif self.front < self.rear:
for i in range(self.front, self.rear):
print(self.queue[i], end = ' ')
else:
for i in range(self.front, self.MAX):
print(self.queue[i], end = ' ')
for j in range(self.rear):
print(self.queue[j], end = ' ')
Your question is a little bit confused. A Queue is an abstract data type that can be implemented in more than one way. Implementing it in an array or list data structure is a standard implementation and straightforward as you can see.
A Binary Search Tree is already an implementation - typically an implementation of an abstract data type like an Ordered Map Container abstract data type. It depends on the ability to (efficiently) create and delete nodes with links to other nodes in them. You typically need to code this implementation in terms of primitives in your language that implement that sort of creation and deletion. Restricting yourself to the array type rules out those primitives.
However, most languages implement those primitives on top of a more primitive layer, your computer process address space (its memory). So you could pretend that the array is like a memory and implement your own allocation and deallocation mechanism on top of that array. Have a look at typical memory allocation algorithms to see what I am talking about.
Of course this is not a good idea in practice, but perhaps you are doing it as a learning experience. It will certainly require some learning!
One other note. You may be thinking about a Heap (as implemented in the Python heapq module). A Heap is not a Binary Search Tree but it has some similarities and is worth learning about.
I've written BSTs, but I don't know how to do it using "array" or "linked list". Here's what me and other people normally do:
class TreeNode:
def __init__(self, val):
self.val = val
self.left = self.right = None
class Tree:
def __init__(self):
self.root = None
def add_node(self, val):
# traversing the tree by comparing val with existing node value
...
def remove_node(self, val):
# whatever...
You store TreeNode in a Tree.

Categories