Alleged misunderstanding in using super [duplicate] - python

I have to do an unrolled linked list for one of my classes. I'm new to python, but not to programming, and for some reason I cannot get around this little problem!
I have a class Node that is to be the node object used within the unrolled linked list. The unrolled linked list class performs all the operations on the Node class.
class UnrolledLinkedList(object):
""" INNER NODE CLASS """
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
""" END NODE CLASS """
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = Node()
""" OTHER FUNCTIONS OF UNROLLEDLINKEDLIST CLASS """
The problem comes at the last line of the UnrolledLinkedList class' init function: "global name Node is not defined". I double checked my indentation and looked all over the internet for examples of something like this, but couldn't find any. Would someone mind explaining to me what's wrong?

Methods do not include their class as a scope to be searched. If you want this to work then you will need to use either UnrolledLinkedList.Node or self.Node instead.

The inner class Node is a member of the class UnrolledLinkedList and can only be accessed via self.
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = self.Node()

Use:
self.head = self.Node()
and it works.
A class does not create its own name space. Using self.Node(), Python first searches all attributes of the instances. Since it does not find the name Node there, it it searches the class UnrolledLinkedList for Node.
Alternatively, you can use the class name directly:
UnrolledLinkedList.Node()
You can achieve the same without nesting the class Node:
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
class UnrolledLinkedList(object):
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = Node()

Qualify Node() with self:
class UnrolledLinkedList(object):
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = self.Node()
Python needs to qualify references to things. In this case, you could either say UnrolledLinkedList.Node() or self.Node().

Related

Best practice in Python for accessing self in another Class

For example if I have 2 classes Tree and Node, in the add_node method in Tree, I can add self referring to the Tree into the Node object as shown below. This is done for convenience when accessing other parts of the Tree with just the keys once in the Node object (i.e. can just use keys). However, I was wondering if this was considered best practice since the IDE (PyCharm) also screams Unresolved attribute reference 'tree' for class 'Node' so might be not a great sign as well.
class Tree:
def __init__(self):
self.nodes = {}
def add_node(self, count):
new_node = Node()
new_node.tree = self
self.nodes[count] = new_node
class Node:
def __init__(self):
# Some data e.g. parent, children index
pass
Pass the tree in the initializer for the Node
class Node:
def __init__(self, tree):
self.tree = tree
And when creating the node:
...
new_node = Node(self)
self.nodes[count] = new_node
...

Invoke a class function with a parameter in python

Let's say I have a simple linked list class:
class LL:
def __init__(self):
self.next = None
self.previous = None
def next(self):
return self.next
def previous(self):
return self.previous
In this case, I want to invoke previous or next, based on what is passed into a function in another class, like so:
class foo:
def __init__(self):
self.node = LL()
def move(direction):
self.node = self.node.direction
S.t. when it makes a call, it would call self.node.next() or self.node.previous().
Where move("next") would make a call to self.node.next().
This doesn't work. Nor does
self.node = self.node.direction()
How would I go about accomplishing something like this?
I'm not sure how to even formally describe this- assigning a class attribute by calling an alternate class' method via a parameter?
For your case, it would be best to keep it simple with an if statement.
def move(direction):
if direction == 'next':
self.node = self.node.next()
elif direction == 'previous':
self.node = self.node.previous()
else:
#handle the invalid input however you think is best
However, you should rename either the field or the method for both next and previous. I would recommend changing next(self) to getNext(self). Alternately, you could change self.next to self._next to indicate that the field is not intended to be accessed directly.
As #user2357112 demonstrated, your LL class itself has shadowing issues. You'll probably want to modify it to perhaps one of the following:
class LL:
def __init__(self):
self._next = None
self._previous = None
# assign a different name
def next(self):
... do something like move the node to next
... maybe change self._next on the way...
return self._next
# Or make use of property decorator
#property
def previous(self):
... do something like move the node to previous
return self._previous
#previous.setter
def previous(self, value):
... do something to change self._previous
Somehow I still don't think that's what you're after, but to answer the spirit of your question, you can use a dict like a switch statement in your foo() class like so:
class foo:
def __init__(self):
self.node = LL()
def move(direction):
_moves = {
'next': self.node.next,
'previous': self.node.previous,
'nowhere': self.node.nowhere
}
# if you're invoking a method
_moves.get(direction)()
# if you're just referencing an attribute
_moves.get(direction)
Conceptually I think it's more important to think about what you're trying to achieve with LL and foo before proceeding though.

Using a callback function to find the sum of values in a bst (without a global)

I've got a binary search tree full of objects. I'm traversing the tree using a callback function that adds a property of all the objects to a global variable. I've got this working, but I'd like to find a way to accomplish this without using a global.
Here's the relevant code:
TOTAL_AGE = 0.0
class Node(object):
def __init__(self, data):
self.left = None
self.right = None
self.data = data
class Tree(object):
def __init__(self):
self.root = None
self.size = 0
def traverse(self, callback):
self._traverse(callback, self.root)
def _traverse(self, callback, node):
if node is None:
return
self._traverse(callback, node.left)
callback(node.data)
self._traverse(callback, node.right)
def add_ages(tree):
tree.traverse(callback)
def callback(student):
global TOTAL_AGE
TOTAL_AGE += student.age
def main():
tree = bst.Tree()
add_ages(tree)
print TOTAL_AGE
This is admittedly for an assignment, which requires that I use the current traverse function and not a different implementation. That's mainly my issue though because I don't see a way to do this without using a global or modifying traverse().
Thanks in advance for any help.
You could pass a method of a class instance as callback so that you can keep track of the state in the instance:
class Count(object):
def __init__(self):
self.total_age = 0
def callback(self, student):
self.total_age += student.age
And then instantiate Count and pass its callback method to the Tree:
count = Count()
tree.traverse(count.callback)

Python - How can I access variables of an above class within a class within a list?

I'm not sure if this is possible within the language or not, but imagine this:
class Parent(object):
def __init__(self, number):
self.variable_to_access = "I want this"
self.object_list = []
for i in range(number): self.object_list.append(Object_In_List(i))
class Object_In_List(object):
def __init__(self): pass
def my_method(self):
# How can I access variable_to_access
I have over simplified this but I was thinking Object_In_List could inherit Parent but Parent will contain many other items and I am concerned about memory usage.
I want to avoid passing the variable_to_access itself constantly. Is this actually possible to access variable_to_access within my_method()?
Thanks
Here is a slightly more complicated example which behaves like Java inner classes
class Parent(object):
def __init__(self, number):
self.variable_to_access = "I want this"
self.object_list = [] for i in range(number):
# Pass in a reference to the parent class when constructing our "inner class"
self.object_list.append(Object_In_List(self, i))
class Object_In_List(object):
# We need a reference to our parent class
def __init__(self, parent, i):
self.parent = parent
# ... So we can forward attribute lookups on to the parent
def __getattr__(self, name):
return getattr(self.parent, name)
# Now we can treat members of the parent class as if they were our own members (just like Java inner classes)
def my_method(self):
# You probably want to do something other than print here
print(self.variable_to_access)
class Parent(object):
def __init__(self, number):
self.variable_to_access = "I want this"
self.object_list = []
for i in range(number):
self.object_list.append(Object_In_List(self.variable_to_access, i))
class Object_In_List(object):
def __init__(self, parent_var, i):
self.pv = parent_var
def my_method(self):
# How can I access variable_to_access
# self.pv is what you want
Right now it seems the only place that any Object_In_List objects exists are within the Parent attribute self.object_list. If that is the case then you are in the Parent class when accessing the Object_In_List already, so you don't even need my_method in Object_In_List. If these objects exist outside of that list then you would have to pass the Parent object or variable anyway, as shown in the other answers.
If you want to be creative you could play with class attributes of Parent. This would not be as "variable" though, unless your class attribute was a dictionary, but then there is the memory thing.

Python class and variables

Learning Python and I ran into some problems when I was working on making a linked list class.
This is just a quick node and dirty node class. In java I would of down private Node next and private int val but I only knew of global as the python cousin. How does this look?
#class Node class
class Node(object):
global next
global val
def __init__(self):
next
val
def setNext(self, aNext):
self.next = aNext
def getNext(self):
return self.next
def setVal(self, aVal):
self.val = aVal
def getVal(self):
return self.val
Then I tried to use a Node in another class with
from Node import *
head = Node()
How ever I am getting an error of undefined variable. Sorry for the simple question just new to python. Appreciate the help.
I would implement this this way:
class Node(object):
def __init__(self, next=None, val=None):
self.next = next
self.val = val
That's it. No getters or setters - Python doesn't use them. Instead, you refactor into a property if you need to move away from the basic attribute reference logic.
You can then create nodes with or without values or successors:
tailnode = Node()
tailnode.val = 'foo'
midnode = Node(val='bar')
midnode.next = tailnode
headnode = Node(val='baz', next=midnode)
You don't need the "global val" / "global next" .. It's a mistake even.
instead just write
val = None
next = None
and initiate them in the __init__()
Meaning, the first lines in your class should be like:
class Node(object):
# You can choose whether to initialize the variables in the c'tor or using your setter methods
def __init__(self, val=None, next=None):
self.next = next
self.val = val
If you really want private variables in Python… then you don't want private variables, and should read Peter DeGlopper's answer.
If you still really, really want private variables in Python… well, you can't have them. But you can have "cooperatively private" variables—variables that nobody will find unless they go looking for them, and that won't clutter the screen when you introspect things in the interpreter, and so on, and, most importantly, that Python programmers know, by convention, that they aren't supposed to touch. All you have to do is start the name with an underscore.
However, your code isn't creating member variables at all, for a number of reasons.
First, global does not declare or define a variable; all it does is tell Python, "when you see this variable later, don't use the normal rules to figure out if it's local or global, always use the global copy". You still have to assign a value to the variable somewhere; otherwise, you'll get a NameError.
Next, variables that you assign in the class definition are class members—similar to Java's static members, although not identical. Each class member is shared by all instances of the class. That's not what you want here; each Node is supposed to have its own separate val and next, not share one with all other Nodes, right?
Normal instance member variables are always accessed through dot syntax—as self.foo from inside the class's methods, or as spam.foo from outside.
So, where do you declare those? You don't. Python doesn't declare anything. You can add new members to an object at any time. The usual way to create a standard set of instance members is in the __init__ method:
class Node(object):
def __init__(self):
self._next = None
self._val = None
def setNext(self, aNext):
self._next = aNext
def getNext(self):
return self._next
def setVal(self, aVal):
self._val = aVal
def getVal(self):
return self._val
But really, you can just let the setters create them. That way, you'll catch the error if someone calls getNext without having called setNext first (which is, I assume, illegal).
class Node(object):
def setNext(self, aNext):
self._next = aNext
def getNext(self):
return self._next
def setVal(self, aVal):
self._val = aVal
def getVal(self):
return self._val
Or, alternatively, force the user to initialize the object with valid values at construction time:
def __init__(self, next, val):
self._next = next
self._val = val
Again, there's no good reason to use setters and getters in the first place in Python.
So, the simplest implementation of your class is:
class Node(object):
pass
While the most Pythonic is:
class Node(object):
def __init__(self, next, val):
self.next = next
self.val = val
… which, you'll notice, is Peter DeGlopper's answer, which, as I said at the start, is probably what you want. :)
Python doesn't really use private variables.
Something like this would be best:
class Node(object):
def __init__(self):
self.val = None
self.next = None
Then, you make and set the node like this:
>>> node = Node()
>>> node.val = 5
>>> node2 = Node()
>>> node2 = 1
>>> node.next = node2
>>> node.next.val
1
If you want to create node with Node(5, Node(1)), use:
class Node(object):
def __init__(self, value=None, next=None):
self.value = value
self.next = next

Categories