Delayed Compute with Method Chaining in Python - python

Let say I have a class:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
def add(self, value):
# Add amount 'value' to every element in the results list
def minus(self, value):
# Subtract amount 'value' from every element in the results list
def compute(self):
# Perform computation
Is there a way to do something like:
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
How do I do something like this in python?

Personally, I would have .add(), et al, push the operator and the operand onto a list and then have .compute() walk through the list, computing the answer as it goes.
Operator chaining is easily accomplished by having each operator return self as its final instruction.
For example:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.operations = []
def add(self, value):
# Add amount 'value' to every element in the results list
self.operations.append(('+', value))
return self
def minus(self, value):
# Subtract amount 'value' from every element in the results list
self.operations.append(('-', value))
return self
def compute(self):
results = []
for x in self.results:
for op, value in self.operations:
if op == '+':
x += value
elif op == '-':
x -= value
results.append(x)
return results
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
print(m.compute()) # This would actually run the computations in order

Wow, you guys are fast!
Here is another go also with a stack, but manipulating the results-list:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.stack = []
def add(self, value):
self.stack.append(value)
return self
def minus(self, value):
self.stack.append(-value)
return self
def compute(self):
for s in self.stack:
for index, _ in enumerate(self.results):
self.results[index] += s
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
print m.results
[10, 11, 12]

As #Rob pointed out, you will need some way to store the operators so that the final compute method can be utilized correctly. This solution uses __add__ and __sub__, with a decorator to store the operators. Note, however, that it would be much more efficient to keep a running total of the values that have been pushed to the stack:
import operator as op
from collections import deque
def operator(f):
def wrapper(cls, _):
cls.operators.append(f.__name__.replace('__', ''))
return f(cls, _)
return wrapper
class Math:
def __init__(self):
self.stack = []
self.operators = deque()
#operator
def __sub__(self, _val):
self.stack.append(_val)
return self
#operator
def __add__(self, _val):
self.stack.append(_val)
return self
def compute(self):
_result = 0
while self.stack:
a, *c = self.stack
_result = getattr(op, self.operators.popleft())(_result, a)
self.stack = c
return _result
m = Math()
m1 = m + 5 - 2 + 7
print([m1.stack, m1.operators])
print(m1.compute())
Output:
[[5, 2, 7], ['add', 'sub', 'add']]
10

Here's a string-based approach which requires little brainpower.
class Math:
def __init__(self):
self.stack = '0'
#staticmethod
def wrap(expr):
return '(' + expr + ')'
def _op(self, other, op):
self.stack = ' '.join([Math.wrap(self.stack), op, str(other)])
def add(self, other):
self._op(other, '+')
return self
def mul(self, other):
self._op(other, '*')
return self
def compute(self):
return eval(self.stack)
m = Math()
print(m.add(2).mul(3).compute())

Related

Don't understand this "Recursion depth exceeded" error for singly linked list implementation

I'm having a little bit of trouble running this code in linux for my class. This week we're on singly linked list and the assignment my teacher gave me was to use nodes to represent polynomials and list them in descending order I keep coming across a maximum recursion depth exceed error in my Node class.
Here is the code for Node:
#!/usr/bin/python
import sys
sys.setrecursionlimit(4500)
"""A model containing Node class"""
class Node(object):
"""A single node in a data structure"""
def __init__(self, coefficient, exponent):
self.coefficient=coefficient
self.exponent=exponent
#property
def coefficient(self):
return self.coefficient
#coefficient.setter
def coefficient(self, c):
self.coefficient=c
#coefficient.deleter
def coefficient(self):
del self.coefficient
#property
def exponent(self):
return self.exponent
#exponent.setter
def exponent(self, e):
self.exponent=e
#exponent.deleter
def exponent(self):
del self.exponent
#property
def next(self):
return self.next
#next.setter
def next(self, n):
self.next=n
#next.deleter
def next(self):
del self.next
def __eq__(self, other):
if self.exponent==other.exponent:
return True
else:
return False
def __It__(self, other):
if self.exponent<other.exponent:
return True
else:
return False
def __str(self):
if self.coefficient>=0:
sign="+"
else:
sign=""
return sign +str(self.coefficient) + "X^" +str(self.exponent)
Here is the code for my List class:
#!/usr/bin/python
from NodeModule import Node
class List(Node):
"""Linked list with pre-defined Node class"""
def __init__(self):
self.head=None
self.count=0
def isEmpty(self):
return self.count==0
def getSize(self):
return self.count
def insert(self, index, o, p):
if index<0 or index > self.count:
return False
n=Node(o, p)
if index==0:
n.next=self.head
self.head=n
self.count+=1
return True
walker=self.head
for i in range(index-1):
walker=walker.next
n.next=walker.next
walker.next=n
self.count+=1
return True
def delete(self, index):
if index < 0 or index > self.count:
return False
if index==0:
self.head=self.head.next
self.count-=1
return True
walker=self.head
for i in range(index-1):
walker=walker.next
walker.next=walker.next.next
self.count-=1
return True
def sort(self):
temp1=self.head.exponent
walker=self.head
j=0
while j < self.count:
for i in self.getsize():
walker=walker.next
temp2=walker.next.exponent
if walker.next.exponent > temp1:
insert(0, walker.next.coefficient, walker.next.exponent)
delete(walker.next)
while walker.next is not None:
if walker.next.exponent < walker.next.next.exponent:
insert(self.getsize(), walker.next.next.coefficient, walker.next.next.exponent)
delete(walker.next)
j+=1
def str(self):
if self.isEmpty():
return "\nEnd of Polynomial"
walker=self.head
output=[]
while walker is not None:
output.append(str(walker))
walker=walker.next
return " + " .join(output)
And here's what I'm using to test my code:
#!/usr/bin/python
from NodeModule import Node
from ListModule import List
def readPoly(message):
l=List()
n=input(message)
for i in range(n):
c=input("Enter the coefficient of term %d" % i)
e=input("Enter the exponent of term %d" % i)
l.insert(0, Node(c,e))
return l
def main():
l=readPoly("Enter the number of terms of the polynomial: ")
print l
l.sort()
print l
l.delete(0)
print (l)
if __name__=='__main__':
main()
The interpreter is telling me that the error is on my self.coefficient=c line in my Node class. How can I go about fixing this issue?
You should not have a variable called coefficient and a property with the same name.
Look at your definition of the setter:
#coefficient.setter
def coefficient(self, c):
self.coefficient=c
When calling self.coefficient = c, the same setter will be called again, recursively.
To solve it, you could rename your variable with an underscore (and change all the other parts of your code):
#coefficient.setter
def coefficient(self, c):
self._coefficient = c
On further reading , it looks like you could omit the setters altogether, since they do not serve a purpose in your code. A reduced version of your class Node (with the same functionality) could be:
class Node:
def __init__(self, coefficient, exponent):
self.coefficient = coefficient
self.exponent = exponent
self.next = None
def __str__(self):
return '{}{}X^{}'.format(
'+' if self.coefficient >= 0 else '',
self.coefficient,
self.exponent)

Recursive Alternative/Merge Linked List Function with Multiple Linked List as Arguments?

I'm having trouble working with recursive linked list function with multiple linked list arguments.
So far I have came up with below, with a single linked list and works fine.
def recursive_ll(ll):
if ll == None:
return None
elif ll.next == None:
return LN(ll.value)
else:
return_ll = LN(ll.value, recursive_ll(ll.next))
if return_ll.value == return_ll.next.value:
return_ll = return_ll.next
return return_ll
Result will be:
ll = list_to_ll(['x','g','f','n'])
print(str_ll(recursive_ll(ll)))
x->g->f->n->None
But I am really confused with how I can create recursive linked list function with multiple linked lists as arguments.
For example, def recursive_ll(ll): will be def recursive_ll(ll, ll2):
And returned result would be
ll = recursive_ll(['a','x','b','e'])
ll2 = recursive_ll(['d','f','m'])
a->d->x->f->b->m->e->None
Again, desired result below, combined from two linked list:
a->d->x->f->b->m->e->None
Any help/suggestions will be much appreciated!
You should use classes instead of simple functions as helpers. And accept any iterable as the source for a linked list. If you implement iterators on the linked list class, that would allow trivial conversion between any iterable and a linked list.
The linked list class could be:
class LL:
class iter:
def __init__(self, ll):
self.cur = ll.front
def __iter__(self):
return self
def __next__(self):
if self.cur is None:
raise StopIteration()
val = self.cur.value
self.cur = self.cur.next
return val
def __init__(self, l):
self.front = last = None
for v in l:
ln = LN(v)
if last is None:
self.front = ln
else:
last.next = ln
last = ln
def __str__(self):
answer = ''
for val in self.iter_elt():
answer += str(val) + '->'
return answer + 'None'
def __repr__(self):
return str(self.__class__) + ':' + str(self)
def __iter__(self):
return LL.iter(self)
This immediately allows:
>>> print(LL('abcd'))
a->b->c->d->None
>>> list(LL('abcd'))
['a', 'b', 'c', 'd']
Once this is done, you can declare a Recursive Linked List as a subclass of a Linked List which allows to extract the elements in a merge order if it contains Linked Lists.
You should first add a new method iter_elt in LL class that just calls iter and use that in __str__ to ease the subclassing:
class LL:
...
def __str__(self):
answer = ''
for val in self.iter_elt():
answer += str(val) + '->'
return answer + 'None'
...
def iter_elt(self):
return self.__iter__()
Because now, it is enough to override iter_elt in RLL, and build an iterator that will scan its sublists repeatedly calling iter_elt on them if possible else iter, until all are exhausted. Code could be:
class RLL(LL):
class iter:
def __init__(self, rll):
self.iters = LL(i.iter_elt() if hasattr(i, 'iter_elt') else iter(i)
for i in rll)
self.cur = self.iters.front
self.prev = None
def __iter__(self):
return self
def __next__(self):
try:
elt = next(self.cur.value)
self.prev = self.cur
self.cur = self.cur.next
if self.cur is None:
self.cur = self.iters.front
self.prev = None
except StopIteration:
self.cur = self.cur.next
if self.cur is None:
if self.prev is None:
raise
self.cur = self.iters.front
self.prev = None
else:
if self.prev is None:
self.iters.front = self.cur
else:
self.prev.next = self.cur
elt = self.__next__()
return elt
def iter_elt(self):
return RLL.iter(self)
I totally agree with #Serge Ballesta that you should create a LinkedList class to do this, here's how it could be done the procedural way you're doing things.
Also note that it's not done recursively—but rather "pythonically".
from itertools import chain, zip_longest
class LN:
def __init__(self, value, next=None):
self.value = value
self.next = next
def list_to_ll(l):
if l == []:
return None
front = rear = LN(l[0])
for v in l[1:]:
rear.next = LN(v)
rear = rear.next
return front
def iterate(ll):
while ll is not None:
yield ll.value
ll = ll.next
def str_ll(ll):
return '->'.join(str(v) for v in iterate(ll)) + '->None'
def alternate(ll_1, ll_2):
_NULL = object()
chained = chain.from_iterable(zip_longest(iterate(ll_1), iterate(ll_2),
fillvalue=_NULL))
return list_to_ll(list(v for v in chained if v is not _NULL))
if __name__ == '__main__':
ll_1 = list_to_ll(['a','x','b','e'])
ll_2 = list_to_ll(['d','f','m'])
print(str_ll(alternate(ll_1, ll_2))) # -> a->d->x->f->b->m->e->None

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 - TypeError: object of type '...' has no len()

Here is a class:
class CoordinateRow(object):
def __init__(self):
self.coordinate_row = []
def add(self, input):
self.coordinate_row.append(input)
def weave(self, other):
result = CoordinateRow()
length = len(self.coordinate_row)
for i in range(min(length, len(other))):
result.add(self.coordinate_row[i])
result.add(other.coordinate_row[i])
return result
This is a part of my program:
def verwerk_regel(regel):
cr = CoordinateRow()
coordinaten = regel.split()
for coordinaat in coordinaten:
verwerkt_coordinaat = verwerk_coordinaat(coordinaat)
cr.add(verwerkt_coordinaat)
cr2 = CoordinateRow()
cr12 = cr.weave(cr2)
print cr12
def verwerk_coordinaat(coordinaat):
coordinaat = coordinaat.split(",")
x = coordinaat[0]
y = coordinaat[1]
nieuw_coordinaat = Coordinate(x)
adjusted_x = nieuw_coordinaat.pas_x_aan()
return str(adjusted_x) + ',' + str(y)
But I'm geting an error at "cr12 = cr.weave(cr2)":
for i in range(min(length, len(other))):
TypeError: object of type 'CoordinateRow' has no len()
You need to add a __len__ method, then you can use len(self) and len(other):
class CoordinateRow(object):
def __init__(self):
self.coordinate_row = []
def add(self, input):
self.coordinate_row.append(input)
def __len__(self):
return len(self.coordinate_row)
def weave(self, other):
result = CoordinateRow()
for i in range(min(len(self), len(other))):
result.add(self.coordinate_row[i])
result.add(other.coordinate_row[i])
return result
In [10]: c = CoordinateRow()
In [11]: c.coordinate_row += [1,2,3,4,5]
In [12]: otherc = CoordinateRow()
In [13]: otherc.coordinate_row += [4,5,6,7]
In [14]:c.weave(otherc).coordinate_row
[1, 4, 2, 5, 3, 6, 4, 7]
Iterating over a range of len(something) is very much an anti-pattern in Python. You should be iterating over the contents of the containers themselves.
In your case, you can just zip the lists together and iterate over that:
def weave(self, other):
result = CoordinateRow()
for a, b in zip(self.coordinate_row, other.coordinate_row):
result.add(a)
result.add(b)
return result
Here is the complete solution for the Cart and Item class implementation.
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def getPrice(self):
return self.price
def getName(self):
return self.name
class ShoppingCart:
def __init__(self):
self.list = []
def __len__(self):
return len(self.list)
def add(self, item):
self.list.append(item)
def total(self):
total = 0
for item in self.list:
total = total + item.getPrice()
return total
other is of type CoordinateRow, which does not have a length. Use len(other.coordinate_row) instead. This is the list that does have the length property.

How can I change in Python the return/input type of a list that is implemented as an class attribute?

EDIT (complete rephrase of the problem as the original version (see "original version", later) is misleading):
Here is the setting: I have a object which has a list of objects of type
<class 'One'>. I would like to access this list but rather work with objects
of type <class 'Two'> which is an enriched version of <class 'One'>.
Background (1):
One could be an object that can be stored easily via a ORM. The ORM would handle the list depending on the data model
Two would be an object like One but enriched by many features or the way it can be accessed
Background (2):
I try to solve a SQLAlchemy related question that I asked here. So, the answer to the present question could be also a solution to that question changing return/input type of SQLAlchemy-lists.
Here is some code for illustration:
import numpy as np
class One(object):
"""
Data Transfere Object (DTO)
"""
def __init__(self, name, data):
assert type(name) == str
assert type(data) == str
self.name = name
self.data = data
def __repr__(self):
return "%s(%r, %r)" %(self.__class__.__name__, self.name, self.data)
class Two(np.ndarray):
_DTO = One
def __new__(cls, name, data):
dto = cls._DTO(name, data)
return cls.newByDTO(dto)
#classmethod
def newByDTO(cls, dto):
obj = np.fromstring(dto.data, dtype="float", sep=',').view(cls)
obj.setflags(write=False) # Immutable
obj._dto = dto
return obj
#property
def name(self):
return self._dto.name
class DataUI(object):
def __init__(self, list_of_ones):
for one in list_of_ones:
assert type(one) == One
self.list_of_ones = list_of_ones
if __name__ == '__main__':
o1 = One('first object', "1, 3.0, 7, 8,1")
o2 = One('second object', "3.7, 8, 10")
my_data = DataUI ([o1, o2])
How to implement a list_of_twos which operates on list_of_ones but provides the user a list with elements of type Two:
type (my_data.list_of_twos[1]) == Two
>>> True
my_data.list_of_twos.append(Two("test", "1, 7, 4.5"))
print my_data.list_of_ones[-1]
>>> One('test', '1, 7, 4.5')
Original version of the question:
Here is an illustration of the problem:
class Data(object):
def __init__(self, name, data_list):
self.name = name
self.data_list = data_list
if __name__ == '__main__':
my_data = Data ("first data set", [0, 1, 1.4, 5])
I would like to access my_data.data_list via another list (e.g. my_data.data_np_list) that handles list-elements as a different type (e.g. as numpy.ndarray):
>>> my_data.data_np_list[1]
array(1)
>>> my_data.data_np_list.append(np.array(7))
>>> print my_data.data_list
[0, 1, 1.4, 5, 7]
You should use a property
class Data(object):
def __init__(self, name, data_list):
self.name = name
self.data_list = data_list
#property
def data_np_list(self):
return numpy.array(self.data_list)
if __name__ == '__main__':
my_data = Data ("first data set", [0, 1, 1.4, 5])
print my_data.data_np_list
edit: numpy use a continous memory area. python list are linked list. You can't have both at the same time without paying a performance cost which will make the whole thing useless. They are different data structures.
No, you can't do it easily (or at all without losing any performance gain you might get in using numpy.array). You're wanting two fundamentally different structures mirroring one another, this will mean storing the two and transferring any modifications between the two; subclassing both list and numpy.array to observe modifications will be the only way to do that.
Not sure whether your approach is correct.
A property getter would help achieve what you're doing. Here's something similar using arrays instead of numpy.
I've made the array (or in your case numpy data type) the internal representation, with the conversion to list only done on demand with a temporary object returned.
import unittest
import array
class GotAGetter(object):
"""Gets something.
"""
def __init__(self, name, data_list):
super(GotAGetter, self).__init__()
self.name = name
self.data_array = array.array('i', data_list)
#property
def data_list(self):
return list(self.data_array)
class TestProperties(unittest.TestCase):
def testProperties(self):
data = [1,3,5]
test = GotAGetter('fred', data)
aString = str(test.data_array)
lString = str(test.data_list) #Here you go.
try:
test.data_list = 'oops'
self.fail('Should have had an attribute error by now')
except AttributeError as exAttr:
self.assertEqual(exAttr.message, "can't set attribute")
self.assertEqual(aString, "array('i', [1, 3, 5])",
"The array doesn't look right")
self.assertEqual(lString, '[1, 3, 5]',
"The list property doesn't look right")
if __name__ == "__main__":
unittest.main()
One solution I just came up with would be to implement a View of the list via class ListView which takes the following arguments:
raw_list: a list of One-objects
raw2new: a function that converts One-objects to Two-objects
new2raw: a function that converts Two-objects to One-objects
Here is a the code:
class ListView(list):
def __init__(self, raw_list, raw2new, new2raw):
self._data = raw_list
self.converters = {'raw2new': raw2new,
'new2raw': new2raw}
def __repr__(self):
repr_list = [self.converters['raw2new'](item) for item in self._data]
repr_str = "["
for element in repr_list:
repr_str += element.__repr__() + ",\n "
repr_str = repr_str[:-3] + "]"
return repr_str
def append(self, item):
self._data.append(self.converters['new2raw'](item))
def pop(self, index):
self._data.pop(index)
def __getitem__(self, index):
return self.converters['raw2new'](self._data[index])
def __setitem__(self, key, value):
self._data.__setitem__(key, self.converters['new2raw'](value))
def __delitem__(self, key):
return self._data.__delitem__(key)
def __getslice__(self, i, j):
return ListView(self._data.__getslice__(i,j), **self.converters)
def __contains__(self, item):
return self._data.__contains__(self.converters['new2raw'](item))
def __add__(self, other_list_view):
assert self.converters == other_list_view.converters
return ListView(
self._data + other_list_view._data,
**self.converters
)
def __len__(self):
return len(self._data)
def __eq__(self, other):
return self._data == other._data
def __iter__(self):
return iter([self.converters['raw2new'](item) for item in self._data])
Now, DataUI has to look something like this:
class DataUI(object):
def __init__(self, list_of_ones):
for one in list_of_ones:
assert type(one) == One
self.list_of_ones = list_of_ones
self.list_of_twos = ListView(
self.list_of_ones,
Two.newByDTO,
Two.getDTO
)
With that, Two needs the following method:
def getDTO(self):
return self._dto
The entire example would now look like the following:
import unittest
import numpy as np
class ListView(list):
def __init__(self, raw_list, raw2new, new2raw):
self._data = raw_list
self.converters = {'raw2new': raw2new,
'new2raw': new2raw}
def __repr__(self):
repr_list = [self.converters['raw2new'](item) for item in self._data]
repr_str = "["
for element in repr_list:
repr_str += element.__repr__() + ",\n "
repr_str = repr_str[:-3] + "]"
return repr_str
def append(self, item):
self._data.append(self.converters['new2raw'](item))
def pop(self, index):
self._data.pop(index)
def __getitem__(self, index):
return self.converters['raw2new'](self._data[index])
def __setitem__(self, key, value):
self._data.__setitem__(key, self.converters['new2raw'](value))
def __delitem__(self, key):
return self._data.__delitem__(key)
def __getslice__(self, i, j):
return ListView(self._data.__getslice__(i,j), **self.converters)
def __contains__(self, item):
return self._data.__contains__(self.converters['new2raw'](item))
def __add__(self, other_list_view):
assert self.converters == other_list_view.converters
return ListView(
self._data + other_list_view._data,
**self.converters
)
def __len__(self):
return len(self._data)
def __iter__(self):
return iter([self.converters['raw2new'](item) for item in self._data])
def __eq__(self, other):
return self._data == other._data
class One(object):
"""
Data Transfere Object (DTO)
"""
def __init__(self, name, data):
assert type(name) == str
assert type(data) == str
self.name = name
self.data = data
def __repr__(self):
return "%s(%r, %r)" %(self.__class__.__name__, self.name, self.data)
class Two(np.ndarray):
_DTO = One
def __new__(cls, name, data):
dto = cls._DTO(name, data)
return cls.newByDTO(dto)
#classmethod
def newByDTO(cls, dto):
obj = np.fromstring(dto.data, dtype="float", sep=',').view(cls)
obj.setflags(write=False) # Immutable
obj._dto = dto
return obj
#property
def name(self):
return self._dto.name
def getDTO(self):
return self._dto
class DataUI(object):
def __init__(self, list_of_ones):
for one in list_of_ones:
assert type(one) == One
self.list_of_ones = list_of_ones
self.list_of_twos = ListView(
self.list_of_ones,
Two.newByDTO,
Two.getDTO
)
class TestListView(unittest.TestCase):
def testProperties(self):
o1 = One('first object', "1, 3.0, 7, 8,1")
o2 = One('second object', "3.7, 8, 10")
my_data = DataUI ([o1, o2])
t1 = Two('third object', "4.8, 8.2, 10.3")
t2 = Two('forth object', "33, 1.8, 1.0")
# append:
my_data.list_of_twos.append(t1)
# __getitem__:
np.testing.assert_array_equal(my_data.list_of_twos[2], t1)
# __add__:
np.testing.assert_array_equal(
(my_data.list_of_twos + my_data.list_of_twos)[5], t1)
# __getslice__:
np.testing.assert_array_equal(
my_data.list_of_twos[1:],
my_data.list_of_twos[1:2] + my_data.list_of_twos[2:]
)
# __contains__:
self.assertEqual(my_data.list_of_twos.__contains__(t1), True)
# __setitem__:
my_data.list_of_twos.__setitem__(1, t1),
np.testing.assert_array_equal(my_data.list_of_twos[1], t1)
# __delitem__:
l1 = len(my_data.list_of_twos)
my_data.list_of_twos.__delitem__(1)
l2 = len(my_data.list_of_twos)
self.assertEqual(l1 - 1, l2)
# __iter__:
my_data_2 = DataUI ([])
for two in my_data.list_of_twos:
my_data_2.list_of_twos.append(two)
if __name__ == '__main__':
unittest.main()

Categories