I wanna create a class which consist of parents and children and a recursion method to call the last child :
class MyClass:
def __init__(self,val,child =None):
self.val = val
self.child = child
def findLastChildVal(self):
if self.child ==None:
return self.val
return (...)
c = MyClass("I'm child")
p = MyClass("I'm parent",c)
p.findLastChildVal()
I have no Idea what to write instead of (...). It's confusing.
This is a classic recursion problem, in my opinion it will be much easier to use a static function instead of a member function:
class MyClass:
def __init__(self, val, child =None):
self.val = val
self.child = child
#staticmethod
def find_last_child_val(current_node: MyClass):
if current_node.child == None:
return current_node.val
else:
return MyClass.find_last_child_val(current_node.child)
c = MyClass("I'm child")
p = MyClass("I'm parent", c)
MyClass.find_last_child_val(p)
Update:
Pay attention that searching for a child using a recursion like this, is not efficient. find_last_child_val() runs in O(n) complexity. It is much more efficient to perform n iterations in a for loop instead of a recursion. If you can't think of a way to reduce the tree traversal complexity, I suggest using a different data structure.
Related
To practice python, I made a simple class for a tree structure in which each node can have infinite child nodes.
class Tree():
def __init__(self, children, val):
self.children = children
self.val = val
def add(self, child):
self.children.append(child)
def remove(self, index):
child = self.children[index]
self.children.remove(child)
return child
def print(self):
self.__print__(0)
def __print__(self, indentation):
valstr = ''
for i in range(0, indentation):
valstr += ' '
valstr += self.val
for child in self.children:
child.__print__(indentation + 1)
However, I have a syntax error in the line def print(self):. Where is the error? I have been looking for a long time, and it seems like the right way to define a python function.
I have also tried
#override
def print(self):
self.__print__(0)
to no avail.
In Python 2 print is a keyword, so you can't use it as the name of a function or method.
In Python 2.7 (and maybe other versions) you can override the print statement with a print function and than override that function.
To do that you have to add
from __future__ import print_function
as the first line of your file.
In Python 2 print is a reserved word and cannot be the name of a variable or method or function.
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)
I've got a class that wraps functions with some metadata, in particular a parental relationship with other instances:
class Foo(object):
def __init__(self, func, parent):
self.func = func
self.parent = parent
self.parent_func = self.parent.func
In a few cases, I would like to use Foo to wrap a function that internally calls another Foo's function:
def f(x): return str(x).title()
def g(x): return self.parent_func(x)
a = Foo(f)
b = Foo(g, a)
print b.func("april is the cruellest month")
>>> April Is The Cruellest Month
Problem is that g isn't actually a method until b runs Foo.__init__, so it doesn't have a self.
I'm assuming there's something rather fundamental I'm missing about scoping, object methods, or functions' first-class citizenship status, and would greatly appreciate a point in the right direction.
EDIT: Looks like my above genericized example threw folks off, so I'm adding a more specific example below. The idea of this class is that each instance is an integer property (primality, perfection, its list of factors, etc), and contains a function that tests an integer for the property (returning a bool or an answer, as the case base be).
def f(n): # returns list of factors of n
def s(n): return len(self.parent_func(n))==2 # checks if n is semiprime
factors = Foo(f)
semiprime = Foo(s, factors)
It seems like your question boils down to "how can I dynamically add a method to an object", the the short answer is don't do it (1). Objects can have attributes which can be functions, and that's fine, but these functions do not become methods and don't behave like methods. For example if foo.attr is sum then foo.attr(x) is the same as sum(x) not sum(foo, x).
Your question has a certain functional "aroma" to it, if you wanted to drop the class/object stuff and go the fully functional route you could do something like this:
def identity(x):
return x
def f(n):
return [i for i in range(1, 10) if (n % i == 0)]
def s(factors):
return (len(factors) == 2)
def foo(func, helper=identity):
def innerfunc(n):
return func(helper(n))
return innerfunc
a = foo(f)
print a(6)
# [1, 2, 3, 6]
b = foo(s, a)
print b(5)
# True
If that doesn't appeal to you, I would suggest thinking of the func and parent attributes on your Foo class as data attached to your objects, not as methods, and work out the problem from there. The logic associated with your class should live inside proper methods. These methods can refer to the data as needed. Here's my very simple example:
class Foo(object):
def __init__(self, func, parent=None):
self.func = func
self.parent = parent
def run(self, n):
if self.parent is None:
return self.func(n)
else:
return self.func(self.parent.run(n))
a = Foo(f)
print a.run(6)
# [1, 2, 3, 6]
b = Foo(s, a)
print b.run(5)
# True
(1) Methods belong to a class not an object, so the question should really be how can I attach something to my object that behaves like a method.
As Matthew said, "parental relationship" would point to inheritance. But if you want/have to do it this way, you could use functools.partial:
from functools import partial
class Foo(object):
def __init__(self, func, parent=None):
self.func = partial(func, self)
self.parent = parent
self.parent_func = self.parent.func if parent is not None else None
def f(self, x):
return str(x).title()
def g(self, x):
return self.parent_func(x)
if __name__ == '__main__':
a = Foo(f)
b = Foo(g, a)
print b.func("april is the cruellest month")
When you call a object method, it is called with self as first parameter.
def f(self,x): return str(x).title()
def g(self,x): return self.parent_func(x)
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
I'm trying to build a very lightweight Node class to serve as a Python-based hierarchy search tool. See the definition below.
from functools import reduce
from operator import or_
class Node:
def __init__(self, name):
self.name = name
self.children = []
def add_child(self, child_node):
self.children.append(child_node)
def contains(self, other_node):
if self == other_node:
return True
elif other_node in self.children:
return True
else:
return reduce(or_, [child.contains(other_node)
for child in self.children], False)
def is_contained_by(self, other_node):
return other_node.contains(self)
def __eq__(self, other_node):
return self.name == other_node.name
def __de__(self, other_node):
return self.name != other_node.name
contains seems to be a textbook case of functional programming (pulled directly from Why Functional Programming Matters).
Question: is there a more efficient or Pythonic way of writing contains? I know that map is usually replaced by list comprehension, but I hadn't seen a better way of doing reduce-based recursion.
Thanks,
Mike
===EDITED ... HERE'S THE REDONE CLASS TAKING INTO ACCOUNT THE ANSWER AND COMMENTS===
class Node:
def __init__(self, name):
self.name = name
self.children = []
def add_child(self, child_node):
# Hattip to lazyr for catching this.
if self.contains(child_node) or child_node.contains(self):
raise TreeError('A relationship is already defined.')
else:
self.children.append(child_node)
def contains(self, other_node):
# Hattip to lazyr for pointing out any() and to Jochen Ritzel for
# eliminating the silly child check.
return (self == other_node or
any(child.contains(other_node) for child in self.children))
def is_contained_by(self, other_node):
return other_node.contains(self)
def __eq__(self, other_node):
return self.name == other_node.name
def __de__(self, other_node):
return self.name != other_node.name
def __repr__(self):
return self.name
I think (not tested) that you instead of reduce should use any like this, which will stop on the first hit:
return any(child.contains(other_node) for child in self.children)
By the way, did you mean for a.contains(b) to return False when a == b and len(a.children) > 0?
Edit: If your tree contains a loop, like this:
a = Node("a")
b = Node("b")
a.add_child(a)
a.add_child(b)
then
a.contains(b)
will crash the program. You may want to check for this either in contains or in add_child, depending on which you use the most.