TLDR
class Tree: pass
# is "equivalent" to (in Python3)
class Tree(object): pass
# Class Declaration
But
tree = Tree()
# is not the same as
tree = Tree
# Class instantiation
Long answer
It makes no difference in the class definition, i.e.
class Tree(object): pass
versus
class Tree: pass
However, you cannot instantiate without calling the constructor!
Class instantiation & assignment VERSUS class assignment
When you do
tree = Tree() # instantiation AND assignment
you create a new object of class Tree
and assign it to the variable tree
. But when you do:
tree = Tree # ONLY assignment
you "only" say that tree
references to the class Tree
. Henceforth, the variable tree's value is the class Tree
, not an instance of Tree
.
Thus, when you do
root = Tree
root.right = Tree
root.left = Tree
All 3 variables root
, root.left
and root.right
reference the same object, the class Tree
.
So when you do:
root.right.data = "right"
you don't create a new object, instead you assign the class Tree
to the class variable root.right
(class attribute) and then assign the value "right"
to the Tree
class's data
attribute (class attribute). Thus, since the last affectation to Tree.data
(as a class) is "right"
, then Tree.data
is "right"
.
Additionally
⚠️ What is confusing is the ability of Python to dynamically add class attributes (check this SO answer for explanations). In your second code, you never point to self.left
, self.right
or self.data
, but always to Tree.left
, Tree.right
and Tree.data
.
Proofs
You could check out:
class Tree: pass
root = Tree
root.data = "root"
root.left = Tree
root.left.data = "left"
root.right = Tree
root.right.data = "right"
print(root.data) # prints "right"
print(root.left.data) # prints "right"
print(root.right.data) # prints "right"
You could also check:
x = Tree()
print(x, type(x))
# <__main__.Tree object at 0x123456789> <class '__main__.Tree'>
y = Tree
print(y, type(y))
# <class '__main__.Tree'> <class 'type'>
Or finally:
class Tree: pass
root = Tree
root.left = Tree
print(root == root.left) # True, because references the class
root = Tree()
root.left = Tree()
print(root == root.left) # False, because references two different instances