Anytree NodeMixin - python

I want to use the NodeMixin Module, but it's not really clear to me if I read the documentation how to do that.
https://anytree.readthedocs.io/en/2.8.0/api/anytree.node.html#anytree.node.nodemixin.NodeMixin
I have a BaseClas like this:
from anytree import NodeMixin, RenderTree
class Tree():
def __init__(self, data, parent):
self.data = data
self.parent = parent
self.children = []
def __eq__(self, other):
if isinstance(other, Tree):
return self.data == other.data
else:
return False
def __repr__(self):
return "Tree("+str(self.data)+","+str(self.children)+")"
def __str__(self):
return self.__repr__()
def update_parent(self, new):
self.parent = new
def add_child(self, c):
self.children.append(c)
def rm_child(self, c):
self.children.remove(c)
If I want to use the NodeMixin Module I would need something like this:
class TreeMix(Tree, NodeMixin): # Add Node feature
def __init__(self, name, length, width, parent=None, children=None):
super(TreeMix, self).__init__()
self.name = name
self.length = length
self.width = width
self.parent = parent
if children:
self.children = children
I get this Error Message:
init() missing 2 required positional arguments: 'data' and 'parent'
I create Objects like this:
my0 = TreeMix('0', 0, 0, parent=None)
my1 = TreeMix('1', 1, 0, parent=my0)
my2 = TreeMix('2', 2, 0, parent=my1)
Did I get the Constructor wrong?

Related

Python class iterator

I have a class of the node which contain his parent and want to create iterator on it. Here is my try:
class Node:
def __init__(self, parent=None):
self._parent = parent
def __iter__(self):
self = self.parent
def __next__(self):
if self.parent is None:
raise StopIteration
else:
self = self.parent
return self
But when I try to loop over the instance, it's never stops and returns the same value, what I did wrong?
The reason your code doesn't work is that you're trying to keep track of the current node in the iterator by assigning to self, which is just a local variable, so nothing is actually updated.
The correct way would be to extract an iterator class and keep track of the current node there:
class Node:
def __init__(self, parent=None):
self.parent = parent
def __iter__(self):
return NodeIterator(self)
class NodeIterator:
def __init__(self, node):
self.next_node = node
def __iter__(self):
return self
def __next__(self):
if self.next_node is None:
raise StopIteration
else:
current_node = self.next_node
self.next_node = self.next_node.parent
return current_node
This can be used like so:
root = Node()
inner_1 = Node(root)
leaf_1 = Node(inner_1)
inner_2 = Node(root)
inner_2_1 = Node(inner_2)
leaf_2 = Node(inner_2_1)
for node in leaf_2:
# will loop through:
# leaf_2,
# inner_2_1;
# inner_2,
# root

Creating python objects of same type from nested class

My List class has a nested _Node class within it. With these 2 classes, I can:
Initialize an object of type List within List.
Initialize an object of type _Node within List.
Initialize an object of type List within _Node.
I can't, however, initialize a _Node within a _Node. The last line of the code is below causes NameError: global name '_Node' is not defined
class List:
def __init__(self):
self.root = None
self.brother = None
def set_root(self):
self.root = self._Node()
def set_brother(self):
self.brother = List()
def set_root_next(self):
self.root.set_next()
class _Node:
def __init__(self, next_node=None, data=None):
self.next_node = next_node
self.data = data
def set_next(self):
self.next_node = _Node()
if __name__ == '__main__':
x = List()
x.set_root()
x.set_brother()
x.set_root_next()
How do I solve this? Making the _Node class unnested works but I am planning to have many types of list in the same file. All accompanying nodes will inherit from a single abstract class so keeping this structure is important.
Try using self.__class__() instead
class List:
def __init__(self):
self.root = None
self.brother = None
def set_root(self):
self.root = self._Node()
def set_brother(self):
self.brother = List()
def set_root_next(self):
self.root.set_next()
class _Node:
def __init__(self, next_node=None, data=None):
self.next_node = next_node
self.data = data
def set_next(self):
self.next_node = self.__class__()
if __name__ == '__main__':
x = List()
x.set_root()
x.set_brother()
x.set_root_next()

Derived class doesn't recognise arguments of method from parent

I'm trying to make a set of functions to operate easily through some data.
The problem I'm facing is: it seems to recognize and use methods from the parent class, except one: show(), giving me errors about unexpected arguments.
Here's a sample of the classes:
from treelib import Tree, Node
class Join(Tree):
def __init__(self, id, desc, childs=(), *args, **kwargs):
Tree.__init__(self, *args, **kwargs)
self.id = id
self.desc = desc
self.value = None
self.parent = None
self.childs = None
self.create_node(tag=desc, identifier=id)
for i in childs:
self.paste(self.id, i)
def getSons(self):
sons = self.children(self.id)
return sons
def getID(self):
return self.id
def getDesc(self):
return self.desc
def show(self):
self.show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')
class Get(Tree):
def __init__(self, id, desc, primitive, *args, **kwargs):
Tree.__init__(self, *args, **kwargs)
self.id = id
self.desc = desc
self.parent = None
self.primitive = primitive
self.create_node(tag=desc, identifier=id, data=primitive)
def getID(self):
return self.id
def getDesc(self):
return self.desc
def show(self):
self.show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')
class Primitive():
def __init__(self, value):
self.value = value
def getValue(self):
return self.value
def show(self):
pass
#print '\t -> ' + str(self.value)
If, for example, I do this on another .py
prim = Primitive(0)
get1 = Get("get1", "Some random thing", prim)
get1.show()
it tells me that key is an unexpected argument. I even checked the library's .py file, the argument is there:
def show(self, nid=None, level=ROOT, idhidden=True, filter=None,
key=None, reverse=False, line_type='ascii-ex'):
The create_node() method works just fine! That's what's weird. Any suggestions?
I'm using treelib in Python 2.7
Your method show() calls itself:
def show(self):
self.show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')
Removed it in Get and change it in Join to:
def show(self):
super(Join, self).show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')

Notify parent instance about property change

I have these two classes:
class Status(object):
def __init__(self):
self._message = ''
#property
def message(self):
return self._message
#message.setter
def message(self, value):
self._message = value
class Buddy(object):
def __init__(self, name):
self.name = name
self.status = Status()
def status_updated(self):
# this should be called when self.status.message is changed
and I use them like this:
buddy = Buddy('John')
buddy.status.message = 'Hello world!' # this should call Buddy.status_updated
I want Buddy.status_updated to be called when I modify the message property of Status. How to achieve this?
You'll have to store a reference back to the parent; python values do not track where they are stored (there can be multiple places that refer to your Status() instances):
class Status(object):
def __init__(self, parent=None):
self._message = ''
self._parent = parent
#property
def message(self):
return self._message
#message.setter
def message(self, value):
self._message = value
if self._parent is not None:
self._parent.status_updated()
class Buddy(object):
def __init__(self, name):
self.name = name
self.status = Status(self)
def status_updated(self):
# this should be called when self.status.message is changed
In each case you need somehow to register you want to "listen" to other's object property changes. I would suggest simple solution like this:
class Status(object):
def __init__(self, on_message_change=None):
self._message, self._on_message_change = '', on_message_change
#property
def message(self):
return self._message
#message.setter
def message(self, value):
if self._on_message_change:
self._on_message_change(self._message, value)
self._message = value
class Buddy(object):
def __init__(self, name):
self.name = name
self.status = Status(self.status_updated)
def status_updated(self, old_value, new_value):
print("status changed '%s' -> '%s'" % (old_value, new_value))
b = Buddy("someone")
b.status.message = "init"
b.status.message = "new"
output is:
status changed '' -> 'init'
status changed 'init' -> 'new'

Expanding the class from object

I have some classes:
class Window(object):
def __init__(self, name):
self.wind_name = name
def getWindowName(self):
return 'wnd' + self.wind_name
class Control(object):
def __init__(self, name, wnd):
self.contrl_name = name
setattr(self, 'getWindowName', wnd.getWindowName)
setattr(self, 'wind_name', wnd.wind_name)
def getControlName(self):
return (self.getWindowName(), 'unk' + self.contrl_name)
class Button(Control):
def __init__(self, name, wnd):
super(Button, self).__init__(name, wnd)
def getControlName(self):
return (self.getWindowName(), 'btn' + self.contrl_name)
wnd = Window('MyApp')
btnOK = Button('OK', wnd)
btnOK.getControlName() # work ok., return ('wndMyApp', 'btnOK')
btnOK.wind_name = 'NewApp'
btnOK.getControlName() # does not work properly., return ('wndMyApp', 'btnOK')
How can I extend the class Control|Button from the object of class Window to access the functions getWindowName and field wind_name in objects btnOK?
Is there a way without creating a field self.wnd = wnd in class Control, or add method setWindowName in Window...?
I can not inherit class Control from the class Window! This is not logical.
Python allows inheriting from multiple classes, i.e.
class Button(Control, Window):
...
But in this case you should know exactly what you are doing (speaking of Pythons Method Resolution Order (MRO)). I'd recommend reading this small book: Python Attributes and Methods.
You can use property for attributes
class Window(object):
def __init__(self, name):
self.wind_name = name
def getWindowName(self):
return 'wnd' + self.wind_name
class Control(object):
def __init__(self, name, wnd):
self.contrl_name = name
self.wnd = wnd
setattr(self, 'getWindowName', wnd.getWindowName)
def get_wind_name(self):
return self.wnd.wind_name
def set_wind_name(self, v):
self.wnd.wind_name = v
wind_name = property(get_wind_name, set_wind_name)
def getControlName(self):
return (self.getWindowName(), 'unk' + self.contrl_name)
class Button(Control):
def __init__(self, name, wnd):
super(Button, self).__init__(name, wnd)
def getControlName(self):
return (self.getWindowName(), 'btn' + self.contrl_name)
wnd = Window('MyApp')
btnOK = Button('OK', wnd)
print btnOK.getControlName() # work ok., return ('wndMyApp', 'btnOK')
btnOK.wind_name = 'NewApp'
print btnOK.getControlName()

Categories