In my main method, when I try to test my insert function, after three inserts, the function suddenly throws an error saying it isn't defined.
I'm not really sure how to go about this. My assumption is that it has something to do with the space of the function being capped, and thus instead of going on with the remaining operations, the compiler cannot continue.
class MerkleTree:
def __init__ (self, rootHash, rootNode):
self.rootHash = rootHash
self.rootNode = rootNode
root = MerkleTree(None, None)
class MerkleNode():
def __init__ (self, value, left, right, leafValue):
self.value = value
self.left = left
self.right = right
self.leafValue = leafValue
class Entry():
def __init__ (self, key, value):
self.key = key
self.value = value
class MerkleTreeInterface:
#recursive Insert Helper
def insertHelp(self, root, node):
if (root.rootNode.right != None):
insertHelp(root.rootNode.right, node)
else:
root.rootNode.right = node
#insert function, finds the appropriate available slot to insert data
def insert(self, key, value):
entry = Entry(key, value)
node = MerkleNode(value, None, None, entry)
if(root.rootNode == None):
root.rootNode = node
else:
if(root.rootNode.left == None):
root.rootNode.left = node
elif(root.rootNode.right == None):
root.rootNode.right = node
else:
insertHelp(root, node)
class main():
tree = MerkleTreeInterface()
tree.insert("b", 2)
tree.insert("a", 1)
tree.insert("c", 3)
tree.insert("d", 4)
The expected result is to simply insert everything (so in this case, the list should be [a,b,c,d] when I traverse it (I only want the keys), but upon the 4th insertion, the error occurs. Here is the log:
Traceback (most recent call last):
File "/Users/User/Desktop/temp.py", line 75, in <module>
class main():
File "/Users/User/Desktop/temp.py", line 81, in main
tree.insert("d", 4)
File "/Users/User/Desktop/temp.py", line 42, in insert
insertHelp(root, node)
NameError: name 'insertHelp' is not defined
[Finished in 0.8s with exit code 1]
In the insertHelp method, insertHelp(root.rootNode.right, node) should be self.insertHelp(root.rootNode.right, node).
In the insert method, insertHelp(root, node) should be self.insertHelp(root, node).
You did not get this error while executing:
tree.insert("b", 2)
tree.insert("a", 1)
tree.insert("c", 3)
Because they did not execute insertHelp(root, node). But:
tree.insert("d", 4)
Tried to execute that statement and you got the error.
As the insertHelp method is an instance method, we need to use self.insertHelp to access it.
Search Python instance method vs Static method vs Class method to understand it clearly.
Related
So I created this node class which has an array of children nodes. Now I want to iterate through the children to find the least cost/value total of all the possible paths. I'm applying the depth first search strategy. But after one of my children has undergone an interation, I get a TypeError saying that "NodeType cannot be iterated"
class Node:
def __init__(self, cost):
self.cost= cost
self.children = None
def get(self):
return self.cost
def findMinPath(self):
min_val = 10000
if self.children is None:
return self.cost
for child in self.children:
temp = child.findMinPath()
if temp<min_val:
min_val=temp
return min_val+self.cost
if __name__ =='__main__':
newnode = Node(0)
nodeleft= Node(5)
nodecenter=Node(3)
noderight=Node(6)
newnode.children={nodeleft,nodecenter,noderight}
nodeleft.children=(Node(4))
Nodecenterleft =Node(2)
Nodecenterright = Node(0)
nodecenter.children={Nodecenterleft,Nodecenterright}
Nodecenterleftleft=Node(1)
Nodecenterleft.children ={Nodecenterleftleft}
Nodecenterleftleftright= Node(1)
Nodecenterleftleft.children={Nodecenterleftleftright}
Nodecenterrightleft = Node(10)
Nodecenterright.children={Nodecenterrightleft}
Noderightleft=Node(1)
Noderightright=Node(5)
noderight.children ={Noderightleft,Noderightright}
print (newnode.findMinPath())
The stack trace is as follows:
Traceback (most recent call last):
File "/Users/yashshah/Desktop/Initializer/tree.py", line 45, in
print (newnode.findMinPath())
File "/Users/yashshah/Desktop/Initializer/tree.py", line 17, in findMinPath
temp = child.findMinPath()
File "/Users/yashshah/Desktop/Initializer/tree.py", line 16, in findMinPath
for child in self.children:
TypeError: 'Node' object is not iterable
[Finished in 0.094s]
This line is wrong:
nodeleft.children = (Node(4))
it needs to be:
nodeleft.children = {Node(4)}
Since you can put parens around any expression, Python can't be sure you mean to create a tuple with your version. So your line is the same as:
nodeleft.children = Node(4)
And as I expect you already see, your code then ends up thinking it's iterating over a collection of Node objects, but it's really trying to iterate over a single Node object, which isn't kosher.
I just learned how to create Binary Search Trees in C#. I decided to try to code the same thing in Python 3.x. However, when I got to my Print method, this error showed up:
Traceback (most recent call last):
File "C:\Users\danie\Desktop\Python\BinarySearchTree\BinarySearchTree\BinarySearchTree.py", line 62, in <module>
b.BSTprint()
File "C:\Users\danie\Desktop\Python\BinarySearchTree\BinarySearchTree\BinarySearchTree.py", line 46, in BSTprint
BST.Print(current)
TypeError: Print() missing 1 required positional argument: 'cur'
The problem, I did put in the required positional argument. I tried fixing it myself and found that if I remove the self parameter, it works. However, I always thought you needed to have that self parameter in all of the class methods. I have no idea what is wrong. Here is the code
import random
class BST:
#Node class
class Node:
data = None
left = None
right = None
def __init__(self, d):
self.data = d
first = None
#Add method
def Add(self, d):
#Checks if the Binary Search Tree is empty
if(BST.first == None):
BST.first = BST.Node(d)
#Debugging purposes
#print("Added: {}".format(d))
return;
else:
newNode = BST.Node(d)
cur = BST.first
while(cur != None):
if(cur.data < newNode.data):
if(cur.left == None):
cur.left = newNode
#print("Added: {}".format(newNode.data))
return
else:
cur = cur.left
elif(cur.data > newNode.data):
if(cur.right == None):
cur.right = newNode
#print("Added: {}".format(newNode.data))
return
else:
cur = cur.right
else:
print("Value already in BST")
return
def BSTprint(self):
current = BST.first
if(current == None):
return
BST.Print(current)
def Print(self, cur):
if(cur.left != None):
BST.Print(cur.left)
print(cur.data)
if(cur.right != None):
BST.Print(cur.right)
b = BST()
#Adds values into BST
for i in range(10):
x = random.randint(1,100)
b.Add(x)
b.BSTprint()
You've got class variables and instance variables mixed up.
In Python, the first argument of methods are reserved for the calling object (except in some cases they aren't, such as in classmethods or staticmethods). Modify the Add method like this:
class BST:
...
def Add(self, d):
if self.first is None:
self.first = BST.Node(d)
return
...
Note that BST.Node(d) is still the same, because I'm referring to something that is belonging to the class: another class.
Modify BST.Print(current) to self.Print(current).
It's uncommon to refer to the root node of a BST as first, prefer root instead!
Things I would like to highlight:
BST is a class
Print is a object method(bound to object and not class) and it requires the object reference to be passed(self) which is different from other languages Java/C++.
You're calling BST.Print which is similar to calling static methods in Java/C++, but its wrong because Print method takes object parameter
Since you're calling a method that is object bound(since it takes self parameter), you need to call it with objects.
The point is:
If you're using methods with self parameter then they should be called with objects. If you want to call them from class then you can use #staticmethod and remove the self parameter and pass the object you want to process
Please refer:
Difference between Class and Instance methods
Hope this helps
As others have noted, in the Print method you need to call BSTprint as an instance method, eg self.BSTprint(node) so that the instance gets passed to the method correctly. But there are a few other issues with your code.
Doing first = None creates first as a class attribute, which means it would be shared by all BST instances. That's not a good idea: each instance should have its own root node! Of course, if the program only creates a single BST instance you wouldn't notice that bug, but if you decide that you want to create several trees then Bad Things would happen. ;)
Instead, you should creates first as an instance attribute, the usual way to do that is in the __init__ method.
Your code defines the Node class inside the BST class. It's fine to do that, but it's a little unusual in Python. It's simpler just to make it a separate class. Once again, you're defining the Node attributes as class attributes. That's actually ok here, since you never modify those class attributes: your Add method creates instance attributes with the same names that "shadow" the class attributes. However, it makes the code a little simpler to analyse if you get rid of those class attributes and simply use instance attributes from the outset.
Here's a modified version of your code. I made a few cosmetic changes so that the code conforms with the Python PEP-0008 style guide. Simple variable, attribute, and method names should begin with lower case letters. I also got rid of redundant parentheses. And it's recommended to use is when testing for the None singleton, it's a little more efficient (and nicer to read) than using == or != value testing.
I changed first to root, in line with Berk Özbalcı's remark. And I gave Node a __repr__ method to make it easier to print the Node data.
I also added a call to random.seed, with a hard-coded seed value so that the program generates the same numbers each time we run it. That makes testing and debugging much easier. It can be hard to figure out what's going wrong when the data keeps changing.
import random
random.seed(42)
class Node:
""" A binary tree node """
def __init__(self, d):
self.data = d
self.left = self.right = None
def __repr__(self):
return repr(self.data)
class BST:
""" Binary search tree """
def __init__(self):
self.root = None
def add(self, d):
# Check if the Binary Search Tree is empty
if self.root is None:
self.root = Node(d)
#Debugging purposes
print("Added: {} root".format(self.root))
return
else:
newNode = Node(d)
cur = self.root
while cur is not None:
if cur.data < newNode.data:
if cur.left is None:
cur.left = newNode
print("Added: {} left".format(newNode))
return
else:
cur = cur.left
elif cur.data > newNode.data:
if cur.right is None:
cur.right = newNode
print("Added: {} right".format(newNode))
return
else:
cur = cur.right
else:
print("Value already in BST:", d)
return
def bst_print(self):
current = self.root
if current is None:
return
self.show(current)
def show(self, cur=None):
if cur.left is not None:
self.show(cur.left)
print(cur)
if cur.right is not None:
self.show(cur.right)
b = BST()
# Add values into BST
for i in range(10):
x = random.randint(1, 100)
print(x)
b.add(x)
print('\nSorted')
b.bst_print()
output
82
Added: 82 root
15
Added: 15 right
4
Added: 4 right
95
Added: 95 left
36
Added: 36 left
32
Added: 32 right
29
Added: 29 right
18
Added: 18 right
95
Value already in BST: 95
14
Added: 14 left
Sorted
95
82
36
32
29
18
15
14
4
I have a handy class that I use to allow me to easily add a set of "summariser" functions to a GDB pretty printer (for example, a Rect class could have an [Area] field, computed by Python). it then prints all the existing children as well, so you can see everything at once.
class SummaryAndFieldIterator:
"""
Iterator to first go through a list of summariser functions,
then display all the fields in the object in order
"""
def __init__ (self, obj, summaries):
self.count = 0
self.obj = obj;
self.summaries = summaries;
self.keys = sorted(obj.type.iterkeys())
def __iter__(self):
return self
def __next__(self):
if (self.count >= len(self.keys) + len(self.summaries)):
raise StopIteration
elif self.count < len(self.summaries):
name, retVal = self.summaries[self.count](self.obj)
# FIXME: this doesn't seem to work when a string is returned
# in retVal?
result = "[%s]" % name, retVal
else:
field = self.count - len(self.summaries)
result = self.keys[field], self.obj[self.keys[field]]
self.count += 1
return result
next = __next__
class MyObjectPrinter:
def __init__(self, val):
self.val = val
def get_int(self):
return "meaning", 42
def get_string(self):
return "hoopiness", "Forty-two"
def children(self):
return SummaryAndFieldIterator(self.val, [self.get_string])
This works very well for the summarisers which return numeric values, but for strings, it ends up displaying as an array, so that I get
NAME VALUE
myobj {..}
|-->[meaning] 42
|-->[hoopiness]
|-->[0] 'F'
|-->[1] 'o'
.....
|-->real_field 34234
This is presumably becuase the string that comes from
name, retVal = self.summaries[self.count](self.obj)
does not generate a sufficiently "stringy" gdb.Value object when it is returned by SummaryAndFieldIterator's __next__ method. Adjusting the display_hint() method of MyObjectPrinter doesn't seem to have any effect (but I doubt it would, as this is the child, not the object).
Anyone know how to return a string from the children() iterator and get it to display as a string?
Okay, apparently this may be a bug related to the way that GDB/MI communicates with pretty-printers, Bugzilla created here : https://sourceware.org/bugzilla/show_bug.cgi?id=18282
Bear with me here; I am a sysadmin not a developer. The following code works just fine for me. But when I break it into two files so that the class is in one file and the logic is in another I get an error that data[0] is a str and does not support assignment
Striped down working example
class partition:
def __init__(self):
self.data = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
return
def boot_flag(self, value=None):
if value is not None:
self.data[0] = value
return
else:
return self.data[0:1][::-1]
part1 = partition()
print str(part1.data).encode('hex')
value = b"\xff"
part1.boot_flag(value)
print str(part1.data).encode('hex')
This is the full class as it stands right now.
class partition:
def __init__(self):
self.data = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
def boot_flag(self, value=None):
if value is not None:
self.data[0] = value
return
else:
return self.data[0:1][::-1]
def start_chs(self, value=None):
if value is not None:
self.data[1:4] = value
return
else:
return self.data[1:4][::-1]
def type(self, value=None):
if value is not None:
self.data[4:5] = value
return
else:
return self.data[4:5][::-1]
def end_chs(self, value=None):
if value is not None:
self.data[5:8] = value
else:
return self.data[5:8][::-1]
def start_lba(self, value=None):
if value is not None:
self.data[8:12] = value
else:
return self.data[8:12][::-1]
def sectors(self, value=None):
if value is not None:
self.data[12:16] = value
else:
return self.data[12:16][::-1]
def load(self, data):
self.data = data
return
This is the test jig I am using to test the class.
import dospart
disk = open('/dev/sda', 'rb')
mbr = disk.read(512)
part1 = dospart.partition()
part1.load(mbr[446:462])
print str(part1.data).encode('hex')
part1.boot_flag(b"\xff")
print str(part1.data).encode('hex')
This is the error
Traceback (most recent call last):
File "test.py", line 13, in <module>
part1.boot_flag(b"\xff")
File "/Users/digitaladdictions/PycharmProjects/dospart/dospart.py", line 9, in boot_flag
self.data[0] = value
TypeError: 'str' object does not support item assignment
Note that I can read the values just fine. I only get an error when I try to write to self.data[]
[UPDATE]
Based on the accepted answer this is my new load function which works.
def load(self, data):
part = bytearray(data)
self.data = part
return
I think this is what is happening. When you invoke:
part1.load(mbr[446:462])
self.data is being assigned a string. And that point on, self.data is a string and not a byte array. So when you do
part1.boot_flag(b"\xff")
it rightly complains TypeError: 'str' object does not support item assignment
This is what I mean:
>>> data_one = "My name is shaktimaan"
>>> data_two = data_one[5:10]
>>> type(data_one)
<type 'str'>
In your first case, there is no invocation of load and hence self.data is still a byte array (after calling the constructor). So your boot_flag works as expected without complaining.
I think you need to fix the code in load to assign byte array to self.data
You can't change Python strings inplace, the're immutable. You can find a lot comments about that error "'str' object does not support item assignmen". I don't know how it can work if you combine it in one file.
First I want to say that I searched for my problem but due to the nature of the problem + the code I have to work with I did not find a solution. Therefore here is my problem:
Traceback (most recent call last):
File "AlienTilesMain.py", line 28, in <module>
goal = astar_search(prob, prob.h1)
File "/home/chris/Desktop/search.py", line 274, in astar_search
return best_first_graph_search(problem, lambda n: n.path_cost + h(n))
File "/home/chris/Desktop/search.py", line 213, in best_first_graph_search
frontier.append(node)
File "/home/chris/Desktop/utils.py", line 738, in append
bisect.insort(self.A, (self.f(item), item))
File "/home/chris/Desktop/utils.py", line 612, in memoized_fn
val = fn(obj, *args)
File "/home/chris/Desktop/search.py", line 274, in <lambda>
return best_first_graph_search(problem, lambda n: n.path_cost + h(n))
File "/home/chris/Desktop/utils.py", line 612, in memoized_fn
val = fn(obj, *args)
File "/home/chris/Desktop/AlienTiles.py", line 57, in h1
n = len(state[0])
AttributeError: Node instance has no attribute '__getitem__'
and my code is this one:
def h1(self, state):
n = len(state[0])
.
.
return value
in my main file:
goal = astar_search(prob, prob.h1)
and here are the Problem, Node Class and A* :
class Problem(object):
def __init__(self, initial, goal):
"""The constructor specifies the initial state, and possibly a goal
state, if there is a unique goal. Your subclass's constructor can add
other arguments."""
self.initial = initial; self.goal = goal
def actions(self, state):
"""Return the actions that can be executed in the given
state. The result would typically be a list, but if there are
many actions, consider yielding them one at a time in an
iterator, rather than building them all at once."""
abstract
def result(self, state, action):
"""Return the state that results from executing the given
action in the given state. The action must be one of
self.actions(state)."""
abstract
class Node:
"""A node in a search tree. Contains a pointer to the parent (the node
that this is a successor of) and to the actual state for this node. Note
that if a state is arrived at by two paths, then there are two nodes with
the same state. Also includes the action that got us to this state, and
the total path_cost (also known as g) to reach the node. Other functions
may add an f and h value; see best_first_graph_search and astar_search for
an explanation of how the f and h values are handled. You will not need to
subclass this class."""
def __init__(self, state, parent=None, action=None, path_cost=0):
"Create a search tree Node, derived from a parent by an action."
update(self, state=state, parent=parent, action=action,
path_cost=path_cost, depth=0)
if parent:
self.depth = parent.depth + 1
def __repr__(self):
return "<Node %s>" % (self.state,)
def expand(self, problem):
"List the nodes reachable in one step from this node."
return [self.child_node(problem, action)
for action in problem.actions(self.state)]
def child_node(self, problem, action):
"Fig. 3.10"
next = problem.result(self.state, action)
return Node(next, self, action,
problem.path_cost(self.path_cost, self.state, action, next))
def solution(self):
"Return the sequence of actions to go from the root to this node."
return [node.action for node in self.path()[1:]]
def path(self):
"Return a list of nodes forming the path from the root to this node."
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def astar_search(problem, h=None):
"""A* search is best-first graph search with f(n) = g(n)+h(n).
You need to specify the h function when you call astar_search, or
else in your Problem subclass."""
h = memoize(h or problem.h, 'h')
return best_first_graph_search(problem, lambda n: n.path_cost + h(n))