Python Forum
Not including a constructor __init__ in the class definition...
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Not including a constructor __init__ in the class definition...
#1
Hello Forum,

We can create a class and include, at the very beginning, the __init__ special method called the constructor which can be parametrized or not. The __init__ method is called anytime an object is created: it constructs objects. The name __init__ stands for initialization because it sets the attributes/methods that every object will have. However, initialization in this case does not mean assigning a specific value to the attributes....Within the class definition, the constructor refers to the specific attributes and methods using the argument self. Self indicates all potential and future instances of the class.

That said, we can also create a class without including the constructor __init__ and still create attributes that all objects will haves...What happens it we don't include the __init__ method? We don't get an error: the __init__ special method is automatically called anyway as the "default constructor". So what is the point of explicitly including __init__ into the class definition if it works by itself anyway?

I have seen the following example:
Class Animal :
     type = "Carnivorous"
     name = "lion"

     def show_output(self):
          print("A" + self.name "is a" self.type)

# Create an instance and call the method
a_lion = Animal()
a_lion.show_output()
thanks!
snippsat write Sep-01-2021, 06:01 PM:
Added code tag in your post,look at BBCode on how to use.
Reply
#2
__init__() is not a constructor. __init__() is a method that gets called after the instance is constructed. It lets you add some code that you want to execute before any other method other than __new__(). I think __new__() is a better fit for "constructor". After __new__() an instance knows how to act like an instance of the class, it just doesn't have any instance variables. I think a better description of __init__() is "initializer".

In your example, type and name are class variables. All Animals will be named "lion" and will be "Carnivorous". All Animals are lions. Not an accurate representation of animals.

Sometimes class variables make sense. All lions are lions and they are carnivores. All lions are also Animals, but not all Animals are lions. Carnivorous lions need something to eat.
class Animal :
    species = None
    type = None

    def __repr__(self):
        return f'{{Animal: Species={self.species}, Type={self.type}}}'

class Lion(Animal) :
     type = "Carnivorous"
     species = "Lion"

class Antelope(Animal) :
     type = "Herbivore"
     species = "Antelope"

# Create an instance and call the method
animals = [Lion(), Antelope()]
print(animals)
But this is still extremely limited. If I worked at a habitat I would not think all lions were the same. I would probably name them and record their birthday and if they were male or female. These are characteristics shared by all animals, so I add them to Animals.
class Animal :
    species = None
    type = None

    def __init__(self, name, gender, dob):
        self.name = name   # These are instance variables.  They can be different for each instance of Animal of subclasses of Animal
        self.gender = gender
        self.dob = dob

    def __repr__(self):
        return f'{{Animal: {self.name}, Gender={self.gender}, Species={self.species}, Type={self.type}, DOB={self.dob}}}'

class Lion(Animal) :
     type = "Carnivorous"
     species = "Lion"

class Antelope(Animal) :
     type = "Herbivore"
     species = "Antelope"

# Create an instance and call the method
animals = [Lion('Leo', 'male', '5, June, 1989'), Antelope('Becky', 'female', '17, August, 2019')]
print(animals)
Animals __init__() method now has to do something special. it initializes three "instance variables". Lion and Antelope can still get by using the default __init__() method.

So sometimes you need an __init__() and sometimes you don't If you want to assign instance variables as soon as an instance is created, you need an __init__(). You never need an __init__() to initialize class variables. If you don't specify an __init__() you get a default which just calls the __init__() of your superclass.
bytecrunch likes this post
Reply
#3
THANK YOU!

Just to be sure, the real constructor is this other special method __new__ while __init__ is the initialization special method....

If we do NOT use the __nit__ method: all instances will have both attributes, i.e. type and name, with exactly the same fixed value, i.e. Carnivore and Lion.

Using __init__, all objects would still have the same two class global attributes, type and name, but we are now able to assign values to those two attributes at the moment when the object is created.

Even without __init__, we could still update the value of the specific attribute of a created instance. Example:
animal_1 = Animal()
animal_1.name= "Gazelle"
Reply
#4
Python really doesn't have "constructors". Python has some special methods that are important in instance creation: __new__() and __init__(). When Python executes leo = Lion() it first calls Lion.__new__() and then calls Lion.__init__(). You can override the default behavior of these methods by providing your own methods. Overriding __new__() is uncommon, but most Python classes will define an __init__() method.

Classes and instances both have attributes. The most common class attributes are functions. They are so common that there is a special name for class functions: methods. But classes can also have attributes that are not methods. These are often called class variables. Lion has class variables species and type. These variables can be accessed by the class and by instances of the class.
class Lion():
    species = 'Lion'
    type = "Carnivore"

print(Lion.species)
leo = Lion()
print(leo.species)
Output:
Lion Lion
Lion.species and leo.species both access the same CLASS attribute. The Lion.species variable was initialized when Python compiled the Lion class code.

You could reassign class variables in the __init__() method, but this would be very unusual I could maybe see doing this for something like an instance counter.
class Lion():
    species = 'Lion'
    type = "Carnivore"
    count = 0

    def __init__(self):
        self.__class__.count += 1

pride = [Lion(), Lion(), Lion(), Lion(), Lion()]
print(Lion.count)
Unless otherwise specified attributes assigned in the __init__() method are "instance" variables. The are unique to an instance.
class Lion():
    name = 'Lion'
    type = "Carnivore"

    def __init__(self, name):
        self.name = name

leo = Lion('Leo')
print(Lion.name, leo.name, type(leo).name)
Because of Python scope rules, self.name = name in the __init__() method creates a new instance variable instead of reassigning the class variable. This is similar to how assigning variables inside a function does not change the value of global variables that just happen to share the same name. Our Lions have a class "name" (Lion) and an instance "name" (Leo). These are completely separate attributes. All Lions will still have the class name "Lion", but there might be only one Lion object named "Leo".

Your example with gazelle is the same. Your assignment animal_1.name= "Gazelle" creates an instance variable "name" in animal_1. It is not setting the Animal class "name".
class Animal():
    name = None

animal_1 = Animal()
animal_1.name = 'Gazelle'
print(Animal.name, animal_1.name)
Output:
None Gazelle
bytecrunch likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  mutable argument in function definition akbarza 1 426 Dec-15-2023, 02:00 PM
Last Post: deanhystad
  error occuring in definition a class akbarza 3 636 Nov-26-2023, 09:28 AM
Last Post: Yoriz
  Function to count words in a list up to and including Sam Oldman45 15 6,414 Sep-08-2023, 01:10 PM
Last Post: Pedroski55
  determine parameter type in definition function akbarza 1 550 Aug-24-2023, 01:46 PM
Last Post: deanhystad
  Why doesn't calling a parent constructor work with arbitrary keyword arguments? PurposefulCoder 4 870 Jun-24-2023, 02:14 PM
Last Post: deanhystad
  Initiating an attribute in a class __init__: question billykid999 8 1,249 May-02-2023, 09:09 PM
Last Post: billykid999
Question __init__ of Child Class zero_fX0 4 1,567 Mar-22-2023, 05:23 PM
Last Post: deanhystad
  [split] Explain the python code in this definition Led_Zeppelin 1 711 Jan-13-2023, 10:20 PM
Last Post: deanhystad
  Explain the python code in this definition Led_Zeppelin 1 1,060 Oct-27-2022, 04:04 AM
Last Post: deanhystad
  meaning of -> syntax in function definition DrakeSoft 5 1,879 Apr-09-2022, 07:45 AM
Last Post: DrakeSoft

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020