Python inheritance: when and why __init__

I'm new to Python trying to understand the philosophy / logic of inheritance methods. The questions ultimately revolve around why and when to use a method __init__

in a subclass. Example:

It seems that a subclass inheriting from a superclass shouldn't have its own constructor (__init__

). Below the dog inherits the attributes (name, age) and methods (makenoise) of the mammal. You can even add a ( do_a_trick

) method . Everything seems to work as it should.

However, if I wanted to add a new attribute to the subclass, as I am trying to do in the Cats class, I get the "self" error. However, I used "I" in defining the class of the dog. What is the nature of the difference? I seem to be defining Cats as I need to use __init__(self,name)

and super()__init__(name)

. Why the difference?

class Mammals(object):

  def __init__(self,name):
    self.name = name
    print("I am a new-born "+ self.name)  
    self.age = 0

  def makenoise(self):
    print(self.name + " says Hello")

class Dogs(Mammals):

  def do_a_trick(self):
    print(self.name + " can roll over")

class Cats(Mammals):

 self.furry = "True"  #results in error `self' is not defined


mymammal = Mammals("zebra") #output "I am a new-born zebra"
mymammal.makenoise()  #output "zebra says hello"
print(mymmmal.age)    #output 0

mydog = Dogs("family pet") #output "I am a new-born family pet"
mydog.makenoise()  #output "family pet says hello"
print(mydog.age)  # output 0
mydog.do_a_trick() #output "family pet can roll over"

      

+3


source to share


7 replies


if I wanted to add a new attribute to a subclass, when I try to do in the Cats class, I get the error "self" is not defined. But I used "I" in defining the class of the dog.

In your superclass Mammal, you have a function __init__

that takes the argument you chose * to call self

. This argument is in scope when you are in the body of a function __init__

- it is a local variable like any local variable and it is not possible to refer to it after its containing function has completed. The function defined in the Dog class do_a_trick

also takes an argument calledself

and it is also local to this function. What makes these variables special is not their name (you could call them whatever), but the fact that, as first arguments to instance methods in python, they receive a reference to the object they are named as their value. (Read this last sentence a few times, this is the key to understanding this, and you probably won't get it the first time.)



Now, in Cat

, you have a line of code that is not in a function at all. At the moment there is nothing in scope including self

, so this fails. If you were to define a function in Cat

that took an argument called self

, it would be possible to refer to that argument. If this argument happened to be the first argument to an instance method on Cat

, then it would have the value of the instance Cat

on which it was called. Otherwise, he would have had everything that was transmitted to him.

* you chose wisely!

+1


source


Explicit is better than implicit.

However, you can do below:

class Dogs(Mammals):
    def __init__(self):
        #add new attribute
        self.someattribute = 'value'
        Mammals.__init__(self)

      



or

class Dogs(Mammals):
    def __init__(self):
        #add new attribute
        self.someattribute = 'value'
        super(Mammals, self).__init__()

      

+2


source


You can do something like Chunky's answer by initializing all the variables in the constructor method i.e. __init__

However, you can also do something like this

class Cats(Mammals):

 furry = "True"

      

And then

cat = Cats("Tom")
cat.furry # Returns "True"

      

The reason you cannot use self

outside of functions is because it self

is explicitly only used for class instances. If you used it outside, it would lead to ambiguity. If my answer is unclear, please let me know in the comments.

+1


source


The method __init__

runs once when the class is instantiated. So if you want to set an attribute on an instance when it was created, then where do you do that. self

is a special keyword that is passed as the first argument to each method and refers to the instance itself. __init__

is no different from other methods in this regard.

"What is the nature of the difference": you define a method Dog.do_a_trick

, and you get it self

as an argument to the method, as usual. But in Cat

you inadvertently (perhaps subconsciously!) Tried to work on the class scope - this is how you should set a class attribute whose value is the same for all cats:

class Cat(object):
    sound = "meow"

      

It differs in that you have both options. Sometimes (not all the time, but occasionally) the class attribute is useful. All cats have the same sound. But most of the time you will be working with instance attributes - different cats have different names; if you need it use __init__

.

+1


source


Declarations at the top level of a Python class become class attributes. If you're coming from a C ++ or Java background, it's like declaring a static member variable. You cannot assign instance attributes at this level.

A variable self

usually refers to a specific instance of the class, the one from which the method was called. When a method call is made using syntax inst.method()

, the first argument to the function is the object inst

on which the method was called. In your case, and usually by convention, this argument is called self

inside the body of the method functions. You can think of it self

as a valid identifier in method bodies. Your assignment is self.furry = True

not being executed in the method, so it is not itself defined there.

You basically have two options to achieve what you want. First, correctly define it furry

as an attribute of the cat class:

class Cat(Mammals):
    furry = True

    # Rest of Cat implementation ...

      

or you can set the value of an instance variable furry

in the cat constructor:

class Cat(Mammals):
    def __init__(self):
        super(Mammals, self).__init__(self)
        self.furry = True

    # Rest of Cat implementation ...

      

If you get into Python, I highly recommend reading these two parts of the Python documentation:

Python classes

Python Data Model Special Methods (More Complex)

+1


source


Suppose you have a named class that has a named Person

method get_name

that is defined as:

 class Person():
     def __init__(self, first_name, last_name):
         self.first_name = first_name
         self.last_name = last_name

     def get_name(self):
         return self.first_name + ' ' + self.last_name

      

And you instantiate Person

like p1

. Now when you call a function get_name()

with this instance it will transform internally

    Person.get_name(p1)

      

So self is the instance itself.

Without, self

you can write the code above:

 class Person():
     first_name = None
     last_name = None


     def get_name(personobject):
         return personobject.first_name + ' ' + personobject.last_name

      

What I am trying to say is the name self

is just a convention.

And for inheritance, if you want to have additional attributes in your subclass, you need to initialize your superclass and add your parameter the way you wanted. For example, if you want to subclass from Person

named Boy

with new attribute height

, you can define it as:

class Boy(Person):
     def __init__(self, first_name, last_name, height):
         super(Person, self).__init__(first_name, last_name)
         self.height = height

      

+1


source


As stated in other answers, self

what you see in the other functions are actually parameters. By Python convention, the first parameter to an instance method is always self

.

Class Cats

inherits the function __init__

of its base class Mammals

. You can override __init__

and you can call or not call the base class.

If you Cats

__init__

want to call the underlying implementation but don't want to worry about the parameters, you can use Python variable arguments. This is shown in the following code.

Class declaration:

class Cats(Mammals):

  def __init__(self, *args):
    super().__init__(*args)
    self.furry = "True"

      

See, for example, this question for something about star notation for a variable number of arguments: Is it possible to pass a variable number of arguments to a function?

Additional test code:

cat = Cats("cat")
print(vars(cat))

      

Output:

I am a new-born cat
{'name': 'cat', 'age': 0, 'furry': 'True'}

      

0


source







All Articles