Issue
I have written this class to create a tree in python:
class Tree:
def init(self, name, cell=""):
self.name = name
self.cell = cell
self.children = []
self.parent = None
def add_child(self, child):
child.parent = self
self.children.append(child)
The data input available requires me to build this tree from the middle in random steps so that there is no way to have the root beforehand. The nodes may not even connect to other nodes at first.
Is there a way to make the last line work? To get the object using its name?
node = Tree("A", cell = "A_cell")
node.add_child(Tree("B", cell = "B_cell"))
node.add_child(Tree("C", cell = "C_cell"))
node.add_child(Tree("D", cell = "D_cell"))
print(Tree("B").cell)
Expected response is "B_cell" but I get an empty string.
Solution
Doing print(Tree("B").cell)
creates a new Tree
instance with the default value for the cell
attribute, an empty string. That object is different from the one created in node.add_child(Tree("B", cell = "B_cell"))
.
If you want to use that syntax (print(Tree("B").cell)
), you would have to avoid generating more than one instance of the class with the same "name" attribute. To achieve this, one option would be to use a metaclass and override the __call__
method, for example:
import weakref
class MetaTree(type):
instances = weakref.WeakValueDictionary()
def __call__(cls, name, cell=""):
if not (instance := cls.instances.get(name)):
instance = cls.__new__(cls)
instance.__init__(name, cell)
cls.instances[name] = instance
return instance
class Tree(metaclass=MetaTree):
def __init__(self, name, cell=""):
self.name = name
self.cell = cell
self.children = []
self.parent = None
def add_child(self, child):
child.parent = self
self.children.append(child)
node = Tree("A", cell = "A_cell")
node.add_child(Tree("B", cell = "B_cell"))
node.add_child(Tree("C", cell = "C_cell"))
node.add_child(Tree("D", cell = "D_cell"))
print(Tree("B").cell)
Note that nothing prevents someone from reassigning another value to the name
attribute of one or more instances once created (node.name = "X"
), which may have unexpected results. In theory the name
attribute should be immutable once the instance is created.
Making an instance attribute immutable (without ways to circumvent it) in Python is... complicated. What is recommended is to avoid that it is modified by mistake, for example using a property without setter:
class Tree(metaclass=MetaTree):
def __init__(self, name, cell=""):
self._name = name
self.cell = cell
self.children = []
self.parent = None
@property
def name(self):
return self._name
def add_child(self, child):
child.parent = self
self.children.append(child)
Answered By - FJSevilla
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.