0

I am a newbie in python and trying my hands in oops programming here. I am initializing base class constructor in derived class , but when trying to print its attribute in base class it gives me errorobject has no attribute

import random
import os
import sys
class Animal:
    __name =""
    def __init__(self,name):
        self.__name = name
    def toString(self):
        return "{} is the animal name".format(self.__name)
    def get_name(self):
        return self.__name
cat = Animal("natasha")
print (cat.toString())
class Dog(Animal):
    __owner = ""
    def __init__(self,name,owner):
        self.__owner= owner
        #Animal.__init__(self,name)
        super(Dog, self).__init__(name)
    def toString(self):
        return "{} is Animal. And owner is: {}".format(self.__name,self.__owner)
rocky = Dog("rocky","Ronchi")
print (rocky.toString())

What am i doing wrong here ? I tried like calling super.get_name() also which was a getter function instead of self.__name but this also did not work.I am working on python3.4

Siva Shanmugam
  • 662
  • 9
  • 19
Invictus
  • 4,028
  • 10
  • 50
  • 80
  • Possible duplicate of [The meaning of a single- and a double-underscore before an object name in Python](http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python) – Łukasz Rogalski Sep 28 '16 at 10:09

4 Answers4

2

This is why you must not use double-underscore prefixes for your instance attributes. These are name mangled, and almost never do what you expect.

Just use self.name and self.owner everywhere.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
2

Replace your method get_name of Animal with the following code

@property
def name(self):
    return self.__name

Also remember to update the toString of Dog to

def toString(self):
    return "{} is Animal. And owner is: {}".format(self.name,self.__owner)

There're some things that I think it's worth point out if you're new to Python:

  • Regarding getters and setters, Python's use the @property and @property.setter decorators instead of the get_something/set_something conventions in language such as Java.
  • Using toString is also not very Pythonic. First, method names should be in snake_case. Second, define a method with the signature def __str__(self) and return a str. Then you'll be able to do print(rocky) without having to call the __str__ as you do for toString.
  • The proper way to use super in Python 3 is just super(), with no arguments passed (https://docs.python.org/3/library/functions.html#super).
怀春춘
  • 197
  • 5
0

Variables starting with double underscores are said as private. They are mangled so they cannot be used in subclasses. Using CPython 3.5, you can confirm it simply with:

>>> rocky.__dict__
{'_Animal__name': 'rocky', '_Dog__owner': 'Ronchi'}
>>>

When called from Dog class, self.__name searches a _Dog__name attribute and cannot find it.

There are two common ways do deal with it:

  • do not use private variables but simply hidden ones, that is just use simple underscore prefixes. The variable will not be displayed by help, but will not be mangled and will be accessible from subclasses
  • use the getter from base class:

    def toString(self):
        return "{} is Animal. And owner is: {}".format(self.get_name(),self.__owner)
    

    This correctly gives:

    >>> print(rocky.toString())
    rocky is Animal. And owner is: Ronchi
    >>> 
    
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • But then in that case should not have super,get_name() a getter function written to retrieve value of name actually get me right stuff when i replaced self.__name with super.get_name()? – Invictus Sep 28 '16 at 10:18
  • @Invictus: no need to call super here. It would make sense only if the method had been overriden in Dog and if you wanted to explicitely call parent's method. – Serge Ballesta Sep 28 '16 at 12:16
0

Actually if you know the concept of abstraction, you've give the name in the parent class as a private key.

import random
import os
import sys
class Animal:

__name =""
def __init__(self,name):
    self._name = name
def toString(self):
    return "{} is the animal name".format(self._name)
def get_name(self):
    return self._name
cat = Animal("natasha")
print (cat.toString())
class Dog(Animal):
__owner = ""
def __init__(self,owner,*args):
    super(Dog, self).__init__(*args)
    self.__owner= owner
def String(self):
    return "{} is Animal. And owner is: {}".format(self._name,self.__owner)
rocky = Dog("rocky","Ronchi")
print (rocky.String())

this is the same code as yours but with little correction, just check it