I created a graph node class in Python.
Each node has single parent, multiple children and properties.
An implementation should be like below:
# graph_test.py
class Node(object):
def __init__(self, name, prop={}):
self.name = name
self.properties = prop
self.parent = None
self.children = []
print "New node:", self.name, self.properties
def add_prop(self, k, v):
self.properties.update({k:v})
print "added prop:", k, v
def add_child(self, n):
self.children.append(n)
n.parent = self
class Foo(object):
def __init__(self, n):
self.node_num = n
self.root_node = None
self.current_node = None
def bas(self):
n = Node("root")
n.add_prop("this_prop_is", "set_only_root_node")
self.root_node = n
return self.root_node
def bar(self):
self.current_node = self.bas()
for i in range(self.node_num):
n = Node(str(i))
self.current_node.add_child(n)
self.current_node = n
if __name__ == '__main__':
f = Foo(5)
f.bar()
In this code, it is expected that only the root node has the property whose key is "this_prop_is".
However, result of execution is like below:
$ python ./graph_test.py
New node: root {}
added prop: this_prop_is set_only_root_node
New node: 0 {'this_prop_is': 'set_only_root_node'}
New node: 1 {'this_prop_is': 'set_only_root_node'}
New node: 2 {'this_prop_is': 'set_only_root_node'}
New node: 3 {'this_prop_is': 'set_only_root_node'}
New node: 4 {'this_prop_is': 'set_only_root_node'}
All nodes have the same key even I add it to only node "root".
I use python 2.7.6.
My questions are:
Is this a bug?
If this is not a bug, why does this occur?
How to fix this issue?
This is not a bug. The problem is your default value for prop. You set it as an empty dictionary. However, this empty dictionary is copied by reference with self.properties = prop and when it is modified, the next time a new Node is created, the modified dictionary is used as the default value.
To fix this, put None as the default value and check for None when assigning properties:
# graph_test.py
class Node(object):
def __init__(self, name, prop=None):
self.name = name
self.properties = prop or {}
self.parent = None
self.children = []
print "New node:", self.name, self.properties
def add_prop(self, k, v):
self.properties.update({k:v})
print "added prop:", k, v
def add_child(self, n):
self.children.append(n)
n.parent = self
class Foo(object):
def __init__(self, n):
self.node_num = n
self.root_node = None
self.current_node = None
def bas(self):
n = Node("root")
n.add_prop("this_prop_is", "set_only_root_node")
self.root_node = n
return self.root_node
def bar(self):
self.current_node = self.bas()
for i in range(self.node_num):
n = Node(str(i))
self.current_node.add_child(n)
self.current_node = n
if __name__ == '__main__':
f = Foo(5)
f.bar()
This is because you have a mutable default value in Node.__init__. In Python, default values are determined when the function is created, and the same instance will always be used. So every time you create a new Node and don't give it an explicit prop argument, it will use the same dictionary.
This is often solved by using None as the default value and creating a new dictionary each time inside the function if the argument is None, for example by doing self.properties = prop or {}. (This will also use a new dictionary if you give it an empty dictionary, but this isn't usually a problem)
Change props={} to props=None and self.properties = prop to self.properties = prop or {}
This is due to the behavior of mutable default arguments in Python. Here's a good resource to read up on this: http://effbot.org/zone/default-values.htm
Related
I am a Javascript engineer and am switching into a JS/Python role. Working on some easy leetcodes to get some quick Python practice.
I'm looking to create a LinkedList here and perhaps I am coming at it from a JS mindset?
Error:
AttributeError: type object 'LinkedListNode' has no attribute 'value'
utils.py
# LinkedList Methods
def createLinkedList(arr):
head = createLinkedListNode(None, arr.pop(0))
def populateList(arr, prevNode):
if arr:
node = createLinkedListNode(None, arr.pop(0))
prevNode.next = node
if arr:
populateList(arr, node)
populateList(arr, head)
return head
def createLinkedListNode(next, value):
class LinkedListNode:
def __init__(self):
self.next = next
self.value = value
return LinkedListNode
deleteNode.py
from python.utils import createLinkedList, linkedListToArray
useCase1 = [4, 5, 1, 9]
linkedList = createLinkedList(useCase1)
^ linkedList.value doesn't exist?
Some misunderstandings with python classes:
The class LinkedListNode should not defined in function.
Return LinkedListNode is actually returning the class itself, but not the Instance. To return the instance, you have to call the class. return LinkedListNode()
Using next as instance variable is not ideal. next is an iteration function in python, so when you set self.next = next, you are actually assigning the function to self.next
If you want to set a variable, for example self.next_value = next_value, you should put next_value as a parameter of __init__ function, like def __init__(self, next_value)
Here is a simple demo of Linked List:
class LinkedList:
def __init__(self, value):
self.value = value
self.next_value = None
def __iter__(self):
yield self.value
if self.next_value is not None:
yield from self.next_value
# else raise StopIteration
def __getitem__(self, index):
if index == 0:
return self.value
else:
return self.next_value[index-1]
# recursively get the next value
def __str__(self):
return str(self.value) + ' -> ' + str(self.next_value)
def __len__(self):
if self.next_value is None:
return 1
else:
return 1 + len(self.next_value)
# recursively get the length
def append(self, value):
if self.next_value is None:
self.next_value = LinkedList(value, self)
else:
self.next_value.append(value)
a = LinkedList(2)
a.append(1)
a.append(3)
for num in a:
print(num, end=", ")
print()
print(a[1])
print(a)
print(len(a))
Output:
2, 1, 3,
1
2 -> 1 -> 3 -> None
3
createLinkedListNode() returns the LinkedListNode class itself, not an instance of the class.
Why are you defining classes and functions inside of other functions? That's an odd way of doing things.
I am a new user of Python annotation. I am trying to achieve dependency by annotation.
class Trie():
def __init__(self):
self.root = self.Node()
self.count = 0
class Node():
def __init__(self, value=None):
self.value = value
self.children = {}
def add(self, key, value):
path = key.split('.')
node = self.root
for token in path:
if token not in node.children:
node.children[token] = self.Node()
node = node.children[token]
node.value = value
self.count += 1
def get(self, key, default_value=None):
path = key.split('.')
node = self.root
for token in path:
if token not in node.children:
return default_value
node = node.children[token]
self.count -= 1
return node.value
_REGISTRY = Trie()
def register_cls(identifier):
def add_class(cls):
_REGISTRY.add(identifier, cls)
return cls
return add_class
def find_cls(identifier, default_value=None):
return _REGISTRY.get(identifier, default_value)
This is the code to register the class and find the class by class name.
But I do not know how to register a class from another file.
#register_cls('resnet18')
class ResNet18:
def __init__(self):
self.name = 'resnet18'
def get_name(self):
return self.name
if __name__ == '__main__':
name_18 = 'resnet18'
model = find_cls(name_18)
print(model().get_name())
assert model().get_name() == name_18
I can only use this function as this test. find_cls() and #register_cls() in the same file. But this code can store the path of the file, how can I use this function to read the class cross different files.
For example, when I have such a Node class defined.
class Node:
def __init__(self, val=None, next=None):
self.val = val
self.next = next
def __bool__(self):
return self.val is not None
When I initialize it with empty arguments, like below. Is there a way to self-define method to say a is None?
a = Node()
a is None # False, but can it be true if I want?
While you cannot override the is comparison, you can at least override the equality operator if you want to quickly check up whether a specific parameter (or condition) within your class should yield True on comparison, e.g.:
class Node:
def __init__(self, val=None, next=None):
self.val = val
self.next = next
def __eq__(self, obj):
return obj == self.val
n = Node()
print(n == None) # True
n = Node(5)
print(n == None) # False
No, but...
You cannot override the is, and, or or operators.
Defining __bool__ allows you to write statements like
class Node:
def __init__(self, val):
self.val = val
def __bool__(self):
return self.val is not None # <--- added "return"
for val in (0, 1, True, None):
n = Node(val)
# These three are equivalent
if n:
assert n.__bool__()
assert n.val is not None
# These three are equivalent
else:
assert not n.__bool__()
assert n.val is None
https://docs.python.org/3/reference/datamodel.html#object.bool
This may not do exactly what you want but you could overwrite the __new__ class method so that, when the class constructor is called with no arguments, the None object is returned instead of an instance of Node.
I think this should work (my metaclass knowledge is spotty).
class Node:
def __new__(cls, val=None, next=None):
if val is None and next is None:
return None
return super().__init__(cls, val, next)
def __init__(self, val, next):
if self is None:
return
...
It is my duty to recommend that you not go down this route, however. Fiddling with __new__ is tricky and dangerous and is probably more trouble than it's worth.
I have a problem with a self-written tree class in python:
class Tree:
def __init__(self, parent=0, value=0):
self.value = value
self.parent = parent
def __iter__(self): return self
def next(self):
tmp = self.value
try:
self.parent = self.parent.parent
self.value = self.parent.value
except AttributeError:
raise StopIteration
return tmp
def sum(self):
list_ = [item for item in self]
print list_
return sum(list_)
Actually, the "tree" is not fully written, but the current problem blocks further progress.
The structure has only two instance variables (value, parent).
I would like to sum values from the current instance to the first parent with iterators (if it is all together possible). The sum method is used for that (additional list_ variable is unnecessary, but helps further to explain the problem).
When running a test case
parent = Tree()
child = Tree(parent=parent, value=8)
child2 = Tree(parent=child,value=10)
print child2.sum()
I obtain the following:
[10]
10
Please, could anybody explain why the list of values contains only one number though it should look like [10,8]? Seems the problem is in the implementation of iter and next, but I can't understand how to repair the solution.
Thank you in advance.
I'm not sure you can call this a Tree. One would expect parent node(s) and multiple leaf nodes, and not just a linear connection of objects.
See: A general tree implementation?
On another note, if you want to implement a linkedlist, suggestions made in the comment to your question by Barny should be considered and as well, you can give an eye to: Python Linked List
Coming to your current implementation, you'll need some sort of loop, to walk from the current child node up until the head parent node. And when the next parent attribute is not found, stop the iteration. The following puts the logic in the __iter__ method of the class, which is now a generator function:
class Tree:
def __init__(self, parent=None, value=0):
self.value = value
self.parent = parent
def __iter__(self):
_parent = self.parent
yield self.value
while True:
try:
yield _parent.value
_parent = _parent.parent
except AttributeError:
break
def sum_from_node(self):
list_ = [item for item in self]
print list_
return sum(list_)
Demo:
parent = Tree()
child = Tree(parent=parent, value=8)
child2 = Tree(parent=child,value=10)
child3 = Tree(parent=child2,value=4)
print child3.sum_from_node()
# [4, 10, 8, 0]
# 22
Here you go:
class Tree:
def __init__(self, parent=None, value=0):
self.value = value
self.parent = parent
def __iter__(self):
yield self.value
root = self
while root.parent is not None:
yield root.parent.value
root = root.parent
raise StopIteration
def tree_sum(self):
return sum(list(self))
parent = Tree()
child = Tree(parent=parent, value=8)
child2 = Tree(parent=child,value=10)
I've changed the default parent value to None.
for i in child2:
print(i)
10
8
0 # 0 is here because the parent value is 0 by default.
I'm trying to design a descriptor class which I can use through other class which is a subclass of a class which is a subclass of a class.
class MyDescriptorClass(object):
def __init__(self, owner, name, activates = 0):
self.value = None
self.name = name
self.owner = owner
self.activates = 0
self.connects = []
def __set__(self, obj, val):
self.set(val)
def __get__(self, instance, owner):
return self.value
def set(self, value):
if self.value == value:
return 0
self.value = value
if self.activates:
self.owner.evaluate()
def connect(self, inputs):
if not isinstance(inputs, list):
inputs = list(inputs)
for input in inputs:
self.connects.append(input)
class ParentClass(object):
def __init__(self, name):
self.states = {}
self.name = name
self.A = MyDescriptorClass(self, name, activates = 1)
self.B = MyDescriptorClass(self, name, activates = 1)
self.states.setDefault('A', self.A)
self.states.setDefault('B', self.B)
class ChildClass1(ParentClass):
def __init__(self, name)
super(ChildClass1, self).__init__(name)
self.ans = None
def evaluate(self):
self.ans = self.A.value + self.B.value
class ChildClass2(ParentClass):
def __init__(self, name)
super(ChildClass1, self).__init__(name)
self.ans = None
def evaluate(self):
self.ans = self.A.value * self.B.value
self.A = MyDescriptorClass() will not work according to the python docs
so the only way is that I declate A = MyDescriptorClass() in the ParentClass as
class ParentClass(object):
A = MyDescriptorClass() # here I am unable to pass the owner
And since, I'm using a child class, super call skips this part and starts directly with __init__
Is there any way in which I can modify the design so as to set the value of ChildClass1.A instance directly?
c = ChildClass1("c1")
c.A = 10 # I directly want to set this value instead of using c.A.set(10)
c.B = 20
c.evaluate()
print c.ans # 30
c.B = 40
print c.ans # 50
Try not to put information which is specific to instances in the descriptor. Keep information specific to instances in instance attributes, and keep information specific to the descriptor (like activates) in the descriptor:
class MyDescriptorClass(object):
def __init__(self, activates = 0):
self.value = None
self.activates = activates
self.connects = []
def __set__(self, instance, val): # 1
if self.value == val:
return 0
self.value = val
if self.activates:
instance.evaluate()
def __get__(self, instance, instcls): # 1
return self.value
Note that the __set__ and __get__ methods are passed the
instance which is accessing the descriptor. Therefore, you do not
need to store the owner in MyDescriptor. The instance is the
owner.
Given the clarification of the problem in the comments below, here is how I would implement the descriptor.
class GateInput(object):
def __init__(self, index):
self.index = index # 4
def __get__(self, inst, instcls):
return inst.inputs[self.index].ans # 5
def __set__(self, inst, val):
if isinstance(val, (float, int)):
inst.inputs[self.index] = Constant(val)
else:
inst.inputs[self.index] = val
class Constant(object):
def __init__(self, val):
self.ans = val
class Gate(object):
A = GateInput(0) # 1
B = GateInput(1) # 1
def __init__(self, name):
self.name = name
self.inputs = [Constant(0), Constant(0)] # 2
class Adder(Gate):
#property
def ans(self):
result = 0
for gate in self.inputs:
result += gate.ans # 3
return result
class Multiplier(Gate):
#property
def ans(self):
result = 1
for gate in self.inputs:
result *= gate.ans
return result
b = Multiplier('b1')
b.A = 2
b.B = 3
print(b.A)
# 2
print(b.ans)
# 6
c = Adder('c1')
c.A = 10
print(c.ans)
# 10
# This connects output of b to an input of c
c.B = b
print(c.ans)
# 16
Descriptors have to be defined as class attributes, not instance
attributes. Since the descriptor is accessed by all instances, you
probably do not want the descriptor to change merely because an
instance is being created. Therefore, do not instantiate the
descriptor in __init__.
Each instance of Gate has a list of inputs. The items self.inputs
are instances of Constant or Gate.
Here we see the purpose of the Constant class. For every gate,
gate.ans needs to return a value.
The index records which item in inst.inputs the GateInput is
connected to.
inst is an instance of Gate. For example, c.A causes Python to
call GateInput.__get__(self, c, type(c)). Thus, inst is c
here.
As it is int he comments:
descriptors must be class attributes, not instance attributes in order to work -
so, to start with:
class ParentClass(object):
A = MyDescriptorClass()
B = MyDescriptorClass()
def __init__(self, name):
self.states = {}
self.name = name
self.A.configure(self, name, activates = 1)
self.B.configure(self, name, activates = 1)
self.states.setDefault('A', self.A)
self.states.setDefault('B', self.B)
And then you fix your Descriptor class accordingly:
either have then keeping all data refering to an instance in the instance itself
(that is why __get__ and __set__ receive the object itself) - or have
each descriptor instance have a dictionary where they can annotate data related
to the instances of the class they belong too, by, for example, object ID.
Your descriptor class could be more or less along these lines:
class MyDescriptorClass(object):
def __init__(self):
self.data = defaultDict(dict)
def configure(self, owner, name, activates = 0):
container = self.data(id(owner))
container["value"] = None
container["name"] = name
...
def __set__(self, owner, value):
# implemnt your previous "set" method straight here
...
...