Python Forum
Class Instances called in the wrong order - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Class Instances called in the wrong order (/thread-24827.html)



Class Instances called in the wrong order - IanIous - Mar-06-2020

Hi,

I started playing around with classes and defined two classes A and B. The first one with a __init__(self) method and the second one without. Just to figure out what happens in __init__

class A:

    def __init__(self):
        print("this is a test")


class B:

    print("this is a second test")


a1 = A()
b1 = B()


The output is the following:
this is a second test
this is a test
Now why exactly does python call the second instance first even though the first instance is first in the code?
Pretty sure this question popped up before but I didn't know how to search for it.

Regards
Ian


RE: Class Instances called in the wrong order - michael1789 - Mar-06-2020

Your major problem is that they aren't really classes.

The _init_ says what the instance will be like the moment it is made. Neither of those have anything about them. They don't make a thing. They are just print statements. Classes are blueprints for making objects.

Now that you have them, you have no way to tell them what to do, because they can't do anything.

Here is a super helpful video you will like:
https://www.youtube.com/watch?v=ZDa-Z5JzLYM&t=1s


RE: Class Instances called in the wrong order - ndc85430 - Mar-06-2020

The answer to the question, though, is that the call to print in B is run when the class is defined (i.e. when the interpreter reads the block under class B:), while the call to print in A is only run when that class' __init__ is called.


RE: Class Instances called in the wrong order - buran - Mar-06-2020

(Mar-06-2020, 04:47 AM)michael1789 Wrote: Your major problem is that they aren't really classes
That statement is not true. This is valid code and they are classes all right. But I will come to that after I answer OP question.

The print function in class B get executed once and only once - at the time of class definition and only then, i.e. it will never be executed again. You are wrong in your assumption that class B print is executed at the time of instance creation (i.e. second).
The print function in class A __init__() method is executed every time when you create new instance of class A.
Now, I doubt you will ever see print function like the one in class B in real code. However you may see class attributes instead. Look at following example:

class Foo:
    spam = 'This is class attribute spam' # this is class attribute shared between all class instances
    eggs = [] # mutable class attribute
    def __init__(self, message):
        self.message = message # this is instance attribute

    def do_something(self):
        print('\nDoing something...')
        Foo.spam = 'I did something'
        Foo.eggs.append(self.message)


print(Foo.spam) # access the class attribute
foo = Foo('This is instance foo') # create instance foo
bar = Foo('This is instance bar') # create instance bar

print('\nAccess instance foo attributes after instantiation')
print(foo.spam)
print(foo.eggs)
print(foo.message)

print('\nAccess instance bar attributes after instantiation')
print(bar.spam)
print(bar.eggs)
print(bar.message)

# change class attribute and instance attribute
Foo.spam = 'New class spam'
foo.message = 'New foo message'

print('\nAccess instance foo attributes after change')
print(foo.spam)
print(foo.eggs)
print(foo.message)

print('\nAccess instance bar attributes after change')
print(bar.spam)
print(bar.eggs)
print(bar.message)

foo.do_something()

print('\nAccess instance foo attributes after call do_something()')
print(foo.spam)
print(foo.eggs)
print(foo.message)

print('\nAccess instance bar attributes after call do_something()')
print(bar.spam)
print(bar.eggs)
print(bar.message)
Output:
This is class attribute spam Access instance foo attributes after instantiation This is class attribute spam [] This is instance foo Access instance bar attributes after instantiation This is class attribute spam [] This is instance bar Access instance foo attributes after change New class spam [] New foo message Access instance bar attributes after change New class spam [] This is instance bar Doing something... Access instance foo attributes after call do_something() I did something ['New foo message'] New foo message Access instance bar attributes after call do_something() I did something ['New foo message'] This is instance bar
@michael1789, if the class is "doing" something does not qualify it as class or not. You can see code like this

class Foo:
    pass
It may be because it's just a placeholder for a class that will be implemented later. Even before being implemented you can see other class inherit from it.
Another common use case is to define custom exceptions, e.g.
class MyError(Exception):
    pass

def make_error():
    raise MyError('This is custom error')

make_error()
Output:
Traceback (most recent call last): File "/home/buran/sandbox/pyforum.py", line 50, in <module> make_error() File "/home/buran/sandbox/pyforum.py", line 48, in make_error raise MyError('This is custom error') __main__.MyError: This is custom error



RE: Class Instances called in the wrong order - IanIous - Mar-06-2020

What a great explanation. Thank you so much!
You guys rock!