-3

I found most guys said there is no difference with or without bracket in class definition. But my codes output different results for it.

#!/usr/bin/env python
class Tree(object):
    def __init__(self):
        self.left = None
        self.right = None
        self.data = None

root = Tree()
root.data = "root"
root.left = Tree()
root.left.data = "left"
root.right = Tree()
root.right.data = "right"

print(root.left.data)

Output: left

While

#!/usr/bin/env python
class Tree:
    def __init__(self):
        self.left = None
        self.right = None
        self.data = None

root = Tree
root.data = "root"
root.left = Tree
root.left.data = "left"
root.right = Tree
root.right.data = "right"

print(root.left.data)

Output : right

So what is the problem behind this

John
  • 1
  • 1
    Both versions print `left`. – Guy Dec 08 '19 at 11:58
  • 3
    You confused class definition with class instantiation. – Klaus D. Dec 08 '19 at 11:59
  • 4
    If you're instantiating a class you **absolutely do** need the parentheses. `root.left = Tree` is *not* the same as `root.left = Tree()`. If you just have `Tree`, you are referencing the class itself, not instantiating it. – khelwood Dec 08 '19 at 12:00

3 Answers3

1

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
Léopold Houdin
  • 1,435
  • 10
  • 17
0

in Python 2 it does make a difference. All classes inherit from object in Python 3. See this answer for more details:

You should really switch to Python 3 anyway, especially if you are getting started. Python 2 will retire on 1st of January 2020.

forkdbloke
  • 1,256
  • 2
  • 9
  • 28
0

When you say root=Tree, you are assigning the class Tree to root. The code

root = Tree
root.left = Tree
root.right = Tree

assign left and right of root to root itself. Since the last assignment is root.right.data = "right" ,root.data gets assigned the value right. Hence root.left.data takes the value right. You can try printing the following:

print(id(root))
print(id(root.left))
print(id(root.right))

They would all have the same values.