0

I'm trying to learn about the basic construction of the python class. I have the following code which is completely running fine:

class Test1:
    name = 'Choton'
    age = 28

class Test2: # __init__ function executes whenever the class is called
    def __init__(self):
        self.name = 'Choton'
        self.age = 28
        print('Class Test2 is called and initialized...')

def main():
    # Test1
    print(f'Test1:')
    print(f'Test1().name = {Test1().name}, Test1().age = {Test1().age}')
    print(f'Test1.name = {Test1.name}, Test1.age = {Test1.age}\n')

    # Test2
    print(f'Test2:')
    print(f'Test2().name = {Test2().name}, Test2().age = {Test2().age}')
    # DOES NOT WORK
    # print(f' name = {Test2.name}, age = {Test2.age}')


if __name__ == '__main__':
    main()

I know that the __init__ function always runs whenever a class is initialized. Here the Test1 class do not have any __init__ function and both Test1.name and Test1().name works fine. But whenever I am calling the name using the __init__ function in Test2, the Test2.name does not work anymore. It says the following error if I uncomment that line: AttributeError: type object 'Test2' has no attribute 'name'.

What is the difference in here? Why both syntax work for one class and not for the other? I am a bit confused about it. Is there any syntactic sugar in here or any generalization that I am missing?

4
  • Test1 has class attributes, which can be accessed either via the class (Test1.x) or an instance of the class (Test1().x). Test2 has only instance attributes, they are not accessible via the class itself. Commented Aug 22, 2022 at 13:42
  • 1
    Test1's name and age are class attributes and Test2's are instance attributes. Print vars(Test1) and vars(Test2) and you will find that Test1 contains 'name' and 'age' while Test2 does not. Commented Aug 22, 2022 at 13:43
  • Hi. Thanks for the answers. But why the class attributes are accessed by both Test1.x and 'Test1().x` ? Shouldn't only Test1.x be working and Test1().x be an error as it is an instance? This seems confusing to me. Commented Aug 22, 2022 at 13:51
  • No, instance still access to the class variables Commented Aug 22, 2022 at 13:55

2 Answers 2

1

Took me a long time to get my head around classes, I'm still not there. The init function isn't needed in every class, one thing it's used for is to allocate different values to the class attributes.

For info,

Test1 is the class.

Test1() is an instance of the class.

Both can be assigned. So you could say:

MyClassInstanceA = Test1()
MyClassInstanceB = Test1()

... These two are different items because they are both instances of the Test1 class, each instance is unique.

Or you could say

MyClassA = Test1
MyClassB = Test1

... These two are the same thing as they are both allocated Test1, not Test1()....

name and age are attributes. In the case of Test1 they are "class attributes". That is, the exist at the class level. They can be accessed via the class or an instance of the class. Remember Test1 is the class Test1() is an instance of the class.

The subtle difference between Test1() and Test1 is what is causing the error.

To further explain. In the Test1 class, the two attributes name and age exist in the class, before we create an instance of the class. If we do create any instances name and age attributes will be the same across all instances. But the important thing here is we don't have to create an instance of the class to access them. That's why Test1.name works....

On the other hand, in Test2 class. The attributes are only created when the class is initiated (this is what the init function is doing). They don't exist until then. So, when we want to access them you need to access them via an instance of the class Test2().name....

MyClassC = Test2

... Still no instance of the class so name or age doesn't exist

MyClassInstanceD = Test2()

... Now we have an instance of the class so name and age exists and it is accessed via that class which is called MyClassInstanceD...

MyClassInstanceD.name = 'Choton'

But as name and age only exist in the instance we can still not call

Test2.name

as this still doesn't exist and never will unless you modify the Test2 class...

Sign up to request clarification or add additional context in comments.

2 Comments

"we don't have to create an instance of the class to access them. That's why Test1.name works...." this line actually answers to my question. Thanks a lot for your efforts :)
One more thing to note, assigning a value to aa class attribute via an instance will over right the attribute for that instance... So Test1.name = "John", Test1().name = "Paul".... For Test1 and any new instances, .name will be "John" but for the Test1() that was created the .name will be "Paul". This one caught me out!!
1

In Test1 you are defining class variables, which are shared between all objects, and can be accessed by using the class only (Test1.name) as well as from the instance (Test1().name). Defining self.name in Test2.__init__ makes it an instance variable, which is only available on a specific instance of the class, e.g. new object created by Test2()

3 Comments

Thanks a lot. But why the class variables are accessed by both class and instance variables? What is the underlying logic behind it? shouldn't Test1().name be an error?
Class variables are meant to represent some state shared by all the objects of a class, why would you want that state to be inaccessible from the instance?
Actually I get it now. thanks for your answer. It really helped.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.