Not sure what i'm doing wrong here. I have this class:
class Node:
'''
Class to contain the lspid seq and all data.
'''
def __init__(self, name,pseudonode,fragment,seq_no,data):
self.name = name
self.data = {}
self.pseudonode = pseudonode
self.seq_no = seq_no
self.fragment = fragment
def __unicode__(self):
full_name = ('%s-%d-%d') %(self.name,self.pseudonode,self.fragment)
return str(full_name)
def __cmp__(self, other):
if self.name > other.name:
return 1
elif self.name < other.name:
return -1
return 0
def __repr__(self):
full_name = ('%s-%d-%d') %(self.name,self.pseudonode,self.fragment)
#print 'iside Node full_name: {} \n\n\n ------'.format(full_name)
return str(full_name)
and putting some entries in a list :
nodes = []
node = Node('0000.0000.0001',0,0,100,{})
nodes.append(node)
>>> nodes
[0000.0000.0001-0-0]
node = Node('0000.0000.0001',1,0,100,{})
nodes.append(node)
>>> nodes
[0000.0000.0001-0-0, 0000.0000.0001-1-0]
i'm trying to get the index of a node in list nodes[]
>>> node
0000.0000.0001-1-0
>>> nodes.index(node)
0
0 is not what i was expecting. Not sure why this is happening.
edit
i'm after getting the index of the list where '0000.0000.0001-1-0' is.
The index function, when used on a container, relies on its element's __cmp__ function to return the index of the first element that it thinks is equal to the input-object. You probably know as much, since you implemented it for the node. But what you are expecting is that __cmp__ considers not only the name, but also the pseudonode and the fragment, right?
A straight-forward approach would be to consider them a tuple, which performs a comparison of elements from left to right, until the first inequality was found:
def __cmp__(self, other):
self_tuple = (self.name, self.pseudonode, self.fragment)
other_tuple = (other.name, other.pseudonode, other.fragment)
if self_tuple > other_tuple:
return 1
elif self_tuple < other_tuple:
return -1
return 0
If you want another order, you can use the tuples-ordering to define it.
Related
I want my Book class to overload the > operator __gt__. So, I can use it in my BookCollection to find the right order.
I used > in InsertBook(). But it is not working! How do I fix it? I want it to be ordered by
the Book’s author (alphabetical / lexicographical order)
the Book’s year of publication
the Book’s title (alphabetical / lexicographical order).
This is my current code for the class Book.py:
class Book:
def __init__(self, title='', author='',year=None):
self.title = title
self.author = author
self.year = year
def setTitle(self, title):
self.title = title
def setAuthor(self, author):
self.author = author
def setYear(self, year):
self.year = year
def getTitle(self):
return self.title
def getAuthor(self):
return self.author
def getYear(self):
return self.year
def __gt__(self,item):
if (0,1,0) > (0,0,0):
return self.author > item.author
else:
return False
if (1,0,0) > (0,0,0):
return self.title > item.title
else:
return False
if (0,0,1) > (0,0,0):
return self.year > item.year
else:
return False
def getBookDetails(self):
return "Title: {}, Author: {}, Year: {}".format(self.title, self.author, self.year)
class BookCollection():
def __init__(self):
self.head = None
def isEmpty(self):
return self.head == None
def insertBook(self, book):
current = self.head
previous = None
stop = False
while current != None and not stop:
if current.getData() > book:
stop = True
else:
previous = current
current = current.getNext()
temp = BookCollectionNode(book)
if previous == None:
temp.setNext(self.head)
self.head = temp
else:
temp.setNext(current)
previous.setNext(temp)
def getNumberOfBooks(self):
temp = self.head
count = 0
while temp != None:
count = count + 1
temp = temp.getNext()
return count
def getAllBooksInCollection(self):
current = self.head
output = ""
while current != None:
output += str(current.getData()) + " "
current = current.getNext()
output = output[:len(output)-1] + "\n"
return output
def getBooksByAuthor(self,item):
current = self.head
found = False
stop = False
while current != None and not found and not stop:
if current.getData() == item:
found = True
else:
if current.getData() > item:
stop = True
else:
current = current.getNext()
return found
I used > in InsertBook(). But it is not working! How do I fix it? I want it to be ordered by
Your overload of the method makes no sense, why are you comparing completely static tuple values? That's always going to do the same thing, so your entire override is really just return self.author > item.author
Overriding __gt__ alone is a bad idea: you really need to override them all or you'll get incoherent result. The functools.total_ordering class decorator allows overriding just __eq__ and one ordering operator, you probably want to use that.
I want it to be ordered by
the Book’s author (alphabetical / lexicographical order)
the Book’s year of publication
the Book’s title (alphabetical / lexicographical order).
Then compare that? I'd recommend a key method or property for simplicity e.g.
#total_ordering
class Book:
#property
def _key(self):
return (self.author, self.year, self.title)
def __eq__(self, other):
return self._key == other._key
def __gt__(self, other):
return self._key > other._key
should do the trick and order your records by ascending author, ascending year of publication, and ascending title
That aside,
Python is not Java
All your trivial getters and setters are useless and redundant, just remove them outright. And getBookDetails should just be the implementation of your __str__.
BookCollection is similarly concerning, isEmpty is not a thing in Python, instead collections implement __len__ (and optionally __bool__ for efficiency). And the entire thing is a mess, why doesn't BookCollection just contain a list of books (or some other collection from the stdlib)? What's the purpose of making it some sort of ad-hoc half-assed linked list?
And it shoudl provide (or use) an iterator, you're implementing the same iteration scheme 3 different times for no reason.
Your naming scheme is also incorrect, Python normally uses snake_case for methods, and properties, and fields.
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!
I'm new to programming, and learning python right now. I am building a system in which every object consists of a singleton elements or binary set (of sets of sets..) containing singleton elements or binary sets, i.e., a recursive structure. Within these objects, I have defined a function that gives me immediate containment, and a recursive function that answers the question whether an element is contained in any of the sets members, recursively. Binary Sets and Singletons are subclasses of the metaclass "syntactic object". Every object has a unique identifier, idx, and every object can in principle occur in multiple places, so we could have a set such as the following, with idx attached to the object as -idx
{{A-0,C-2}-4, {B-1, {C-2, {D-3, {A-0,C-2}-4}-5}-6}-7
class SOMeta(object):
"""Abstract class, never instantiated. Has two subtypes, base case, recursive case"""
def __init__(self, idx: int):
self.idx = idx
def i_contains(self, a):
"""self immediately contains a if a is an element of self"""
if type(self) is Binary:
return a in self.syntactic_object_set
else:
return False
def contains(self, a):
"""self contains a if self immediately contains a, or some daughter of self contains a"""
if type(self) is Binary:
if self.i_contains(a):
return True
else:
to_return = False
for daughter in self.syntactic_object_set:
if type(daughter) is Binary:
to_return = to_return or daughter.contains(a)
return to_return
else:
return False
class Binary(SOMeta):
def __init__(self, the_set: Set[SOMeta], idx: int):
super(Binary, self).__init__(idx)
self.syntactic_object_set: Set[SOMeta] = the_set
def __str__(self):
set_strings = {str(obj) for obj in self.syntactic_object_set}
rep = "< " + str(self.idx) + ": " + ", ".join(set_strings) + " >"
return rep
class Singleton(SOMeta):
def __init__(self, lexical_item: string, idx: int):
super(Singleton, self).__init__(idx)
self.lexical_item = lexical_item
def __str__(self):
rep = "< " + str(self.idx) + ": " + str(self.lexical_item) + " >"
return rep
Now, based on this, I am trying to define a function that returns a set of "paths" of an object within an object, starting at the top, where a path is defined as follows:
a path is a sequence of objects < O_1, O_2,..., O_n > where for all 0 < i < n, O_{i+1} is in O_i.
So, for example, if the set in question is {A-0, {B-1,A-0}-2}-3, I want this function to return the following set of lists:
{[{A-0, {B-1,A-0}-2}-3, A-0], [{A-0, {B-1,A-0}-2}-3, {B-1,A-0}-2, A-0]}
I have tried the following recursive function, which works well in the base cases, and the above case, but seems to run into trouble with larger sets. I suspect that I'm doing something wrong in the way that I try to pass up path_set in the function?
def paths(self, so):
"""
:return: all paths to self starting at so
"""
def paths_recursive(self, other, path, path_set = set()):
""" Helper Function """
for x in so.syntactic_object_set:
if x.idx == self.idx:
path += [self]
path_set.update([tuple(path)])
elif type(x) != Singleton:
if x.contains(self):
path1 = path.copy() # Need to make a copy in case both daughters contain self
path1 += [x]
path_set.update(paths_recursive(self, x, path1, path_set))
return path_set
if so.contains(self) == False:
return {}
elif so.idx == self.idx:
return {self}
else:
return paths_recursive(self, so, list([so]))
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
I programmed a Trie as a class in python. The search and insert function are clear, but now i tried to programm the python function __str__, that i can print it on the screen. But my function doesn't work!
class Trie(object):
def __init__(self):
self.children = {}
self.val = None
def __str__(self):
s = ''
if self.children == {}: return ' | '
for i in self.children:
s = s + i + self.children[i].__str__()
return s
def insert(self, key, val):
if not key:
self.val = val
return
elif key[0] not in self.children:
self.children[key[0]] = Trie()
self.children[key[0]].insert(key[1:], val)
Now if I create a Object of Trie:
tr = Trie()
tr.insert('hallo', 54)
tr.insert('hello', 69)
tr.insert('hellas', 99)
And when i now print the Trie, occures the problem that the entries hello and hellas aren't completely.
print tr
hallo | ellas | o
How can i solve that problem?.
Why not have str actually dump out the data in the format that it is stored:
def __str__(self):
if self.children == {}:
s = str(self.val)
else:
s = '{'
comma = False
for i in self.children:
if comma:
s = s + ','
else:
comma = True
s = s + "'" + i + "':" + self.children[i].__str__()
s = s + '}'
return s
Which results in:
{'h':{'a':{'l':{'l':{'o':54}}},'e':{'l':{'l':{'a':{'s':99},'o':69}}}}}
There are several issues you're running into. The first is that if you have several children at the same level, you'll only be prefixing one of them with the initial part of the string, and just showing the suffix of the others. Another issue is that you're only showing leaf nodes, even though you can have terminal values that are not at a leaf (consider what happens when you use both "foo" and "foobar" as keys into a Trie). Finally, you're not outputting the values at all.
To solve the first issue, I suggest using a recursive generator that does the traversal of the Trie. Separating the traversal from __str__ makes things easier since the generator can simply yield each value we come across, rather than needing to build up a string as we go. The __str__ method can assemble the final result easily using str.join.
For the second issue, you should yield the current node's key and value whenever self.val is not None, rather than only at leaf nodes. As long as you don't have any way to remove values, all leaf nodes will have a value, but we don't actually need any special casing to detect that.
And for the final issue, I suggest using string formatting to make a key:value pair. (I suppose you can skip this if you really don't need the values.)
Here's some code:
def traverse(self, prefix=""):
if self.val is not None:
yield "{}:{}".format(prefix, self.val)
for letter, child in self.children.items():
yield from child.traverse(prefix + letter)
def __str__(self):
return " | ".join(self.traverse())
If you're using a version of Python before 3.3, you'll need to replace the yield from statement with an explicit loop to yield the items from the recursive calls:
for item in child.traverse(prefix + letter)
yield item
Example output:
>>> t = Trie()
>>> t.insert("foo", 5)
>>> t.insert("bar", 10)
>>> t.insert("foobar", 100)
>>> str(t)
'bar:10 | foo:5 | foobar:100'
You could go with a simpler representation that just provides a summary of what the structure contains:
class Trie:
def __init__(self):
self.__final = False
self.__nodes = {}
def __repr__(self):
return 'Trie<len={}, final={}>'.format(len(self), self.__final)
def __getstate__(self):
return self.__final, self.__nodes
def __setstate__(self, state):
self.__final, self.__nodes = state
def __len__(self):
return len(self.__nodes)
def __bool__(self):
return self.__final
def __contains__(self, array):
try:
return self[array]
except KeyError:
return False
def __iter__(self):
yield self
for node in self.__nodes.values():
yield from node
def __getitem__(self, array):
return self.__get(array, False)
def create(self, array):
self.__get(array, True).__final = True
def read(self):
yield from self.__read([])
def update(self, array):
self[array].__final = True
def delete(self, array):
self[array].__final = False
def prune(self):
for key, value in tuple(self.__nodes.items()):
if not value.prune():
del self.__nodes[key]
if not len(self):
self.delete([])
return self
def __get(self, array, create):
if array:
head, *tail = array
if create and head not in self.__nodes:
self.__nodes[head] = Trie()
return self.__nodes[head].__get(tail, create)
return self
def __read(self, name):
if self.__final:
yield name
for key, value in self.__nodes.items():
yield from value.__read(name + [key])
Instead of your current strategy for printing, I suggest the following strategy instead:
Keep a list of all characters in order that you have traversed so far. When descending to one of your children, push its character on the end of its list. When returning, pop the end character off of the list. When you are at a leaf node, print the contents of the list as a string.
So say you have a trie built out of hello and hellas. This means that as you descend to hello, you build a list h, e, l, l, o, and at the leaf node you print hello, return once to get (hell), push a, s and at the next leaf you print hellas. This way you re-print letters earlier in the tree rather than having no memory of what they were and missing them.
(Another possiblity is to just descend the tree, and whenever you reach a leaf node go to your parent, your parent's parent, your parent's parent's parent... etc, keeping track of what letters you encounter, reversing the list you make and printing that out. But it may be less efficient.)