Why while running the program I am getting object not callable - python

class College():
def __init__(self,name):
self.name = name
def name(self):
print(self.name)
a = College("IIT")
a.name()

You gave a an instance attribute named name when you called College.__init__. That shadows the class attribute (i.e., the method) with the same name. Choose a different method or attribute name.
a.name is the string "IIT", which is not callable. You can cheat a bit to get access to the method
>>> College.name(a)
IIT
but it will be cleaner to use separate names for the two attributes.

You are getting this because when you are calling the name() method but the program (python compiler) thinks that you are calling the name attribute of that object.
To prevent that from happening this just use a different name for every methods, attributes and variables.
class College():
def __init__(self,name):
self.name = name
def show_name(self):
print(self.name)
a = College("IIT")
a.show_name()

Related

What is the point of using private variables if we also use the property decorator in Python?

Consider the following class:
class Product:
def __init__(self, entity_id, name, price):
self.entity_id = entity_id
self.name = name
self.price = price
We can just access and change the attributes of an instance of the Product class. So we can do something like this:
product1 = Product(1, "p1", 100)
product1.name = "p2"
And we can change that attribute directly. We might not want that, so we can use double underscore to prevent this:
class Product:
def __init__(self, entity_id, name, price):
self.__entity_id = entity_id
self.__name = name
self.__price = price
And now we cannot access those attributes directly anymore. We need to use the getter and setter methods that we define within the class. The following wouldn't work:
product1 = Product(1, "p1", 100)
product1.__name = "p2" # we can't do this
So this is why we define something like this within the class:
def set_name(self, name):
self.__name = name
And we call this method outside the class to change the name. We can't change that attribute directly, we have to use the setter method.
If we were to use properties:
class Product:
def __init__(self, entity_id, name, price):
self.__entity_id = entity_id
self.__name = name
self.__price = price
#property
def name(self):
return self.__name
#name.setter
def name(self, name):
self.__name = name
The attributes are still private, but we can change the private attribute name by just doing this:
product1 = Product(1, "p1", 100)
product1.name = "p2"
So then, my question is: What is the point of using private variables if we can just change them directly, now that we used properties? I thought the point of private variables is to prevent direct access to the attributes of a class instance directly, so that we can't (directly) change them outside the scope of the class, we'd have to use a getter/setter. But if we use properties, all of that goes out the window. We can change the attributes outside the scope of the class. So what is the point of using private variables if we also use the property decorator in Python? I don't know if I made my question clear, I'm really confused about this.
Think like this:
Define your attribute as public name, because well, there is way to make it private in Python.
class Product:
def __init__(self, name):
self.name = name
If name is an implementation detail of your class, hint that to the class users by renaming it to _name. Nothing changes, this is only a convention saying, "this is for internal use only, and can change in the future; do not touch, or go ahead at your own risk".
class Product:
def __init__(self, name):
self._name = name
If you want to annoy a bit your class users, rename it to __name. This is discouraged by many Pythonists, because it does not prevent access, it justs causes an error on direct access (this is actually meant to mangle the name with the class name to prevent clashes, not give privacy).
class Product:
def __init__(self, name):
self.__name = name
>>> p = Product("Cube")
>>> p.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Product' object has no attribute '__name'
>>> p._Product__name
'Cube'
Instead, and if you want to make an attribute read-only, define a property name, changing the the underlying name to _name (the internal class value you return in your getter).
class Product:
def __init__(self, name):
# hint privacy only, using _
self._name = name
#property
def name(self):
return self._name
If you actually want it to be changed too, define the property setter, making it writable on one hand, and allowing the execution of validation code, a common requirement when you allow writes. Both the getter and the setter can be used to intercept attribute access at runtime, and run additional code with whatever class internal side effects you might need.
#name.setter
def name(self, value):
# maybe validate the value
if name_is_valid(value):
self._name = value
else:
raise ValueError("Invalid Product name")
This is what you actually need to know to use properties most of the time, without having to worry about decorators and descriptors (an advanced concept, properties are actually a descriptor).

Python Inheritance:Attribute error when using a parent method to print out a inherited variable

I am new to python inheritance, and I met a simple issue just to
print out variables.
I have a parent class prints
class prints:
def __init__(self):
self.__name = ""
def getName(self):
return self.__name
class A(prints):
def __init__(self):
self.__name = "A"
a = A()
n = a.getName()
print(n)
I got an error
AttributeError: 'A' object has no attribute '_prints__name'
I know I can do it in C++, but I am scratching my head to figure out
where is wrong in my python code..
Could someone help? Thanks!
Python doesn't implement private variables but it does help reduce the risk of name clashes with variables you'd like to keep private to a class. If your instance variable starts with two underscores, python will prepend the class name. See "name mangling" in Private Variables So, the prints __name variable is renamed _prints__name.
This method works, except when it doesn't. Inherited classes don't have a natural way to get to the variable. Generally this isn't a problem because it is class private after all. One way to use it is to call methods in the base class. In this case, you likely should have called the base class __init__ to set the variable. But if you want to use it directly, you can do self._prints__name.
class prints:
def __init__(self):
self.__name = ""
def getName(self):
return self.__name
class A(prints):
def __init__(self):
self._prints__name = "A"
a = A()
n = a.getName()
print(n)
The problem is that you are using a variable with prefix __.
Officially python does not have private variables, but when you use a var with prefix __, the it stored as _className__var,
If you peek inside a.__dict__:
a.__dict__
Out[9]: {'_A__name': 'A'}
So, when you do a.getName(), inheritance logic that you would expect kicks in
that searches parent for getName by looking at prints.__dict__(which finds a match)
This would attempt to resolve __name of the parent, except in this case it would be looking to resolve it as _prints__name of self which is an instance of A.
This is called name mangling
class prints:
def __init__(self, name):
self.name = ""
def getName(self):
return self.name
class A(prints):
def __init__(self):
self.name = "A"
a = A()
n = a.getName()
print(n)
refer to basics in python https://www.w3schools.com/python/python_inheritance.asp

AttributeError: 'person' object has no attribute 'name'

class Name():
def full_name(self):
self.firstname='[no name]'
self.lastname='[no name]'
class person:
def detail(self):
self.name=Name()
self.eye='[no eye]'
self.age=-1
myperson=person()
myperson.name.firstname='apple'
myperson.name.lastname='regmi'
myperson.name.firstname='cat'
print(myperson.name.firstname)
i could not find out why iam getting line 13, in
myperson.name.firstname='apple' AttributeError: 'person' object has no attribute 'name'
It seems like you're hoping to set the name, eye, and age attributes as defaults when you create any person object. If that's the case, detail should really be replaced with __init__, e.g.:
class person:
def __init__(self):
self.name=Name()
self.eye='[no eye]'
self.age=-1
A class's __init__ method defines how objects should be initialized when they are created. You don't need to call this method explicitly; instead, it is automatically run when you create an instance of a class:
# create an instance of persion, call
# `person.__init__()`, and assign the result
# to `myperson`:
myperson = person()
Now you should be able to reference and assign the attributes:
myperson.name.firstname='apple'
myperson.name.lastname='regmi'
myperson.name.firstname='cat'
Similarly, name.full_name should probably be name.__init__.
Note that by convention, classes in python usually use TitleCase, so this class would typically be named Person; likewise, name would be Name.

Looks like base class constructor not initialized

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
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.
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).
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
>>>
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

Issue in calling the base class methods

I am newbie in Python.I know this question is useless.But I am frustrated with my issue.I have 2 methods defined in my base class Animals.When I try to call the base methods in my inherited classes it shows these error:
NameError: name 'display_name' is not defined
class Animals():
def display_name(self):
print ('Name is Mr.X')
def display_age(self):
print('Age is 25')
class Name(Animals):
display_name(self)
class Age(Animals):
display_age(self)
n=Name()
a=Age()
n.display_name()
a.display_age()
You need to refer to the display_name function with a self prefix instead of passing self as an argument.
Also, as noted by Antimony, you need to call the display_name from within a function that is associated with an instance of the class (inside a function that accepts the self argument).
Code that appears outside a method function but inside a class is associated with the whole class, not with any particular instance of that class - using the self variable in this context has no meaning - if you create multiple objects from the class which one does it refer to?
class Animals():
def display_name(self):
print ('Name is Mr.X')
def display_age(self):
print('Age is 25')
class Name(Animals):
def call_display_name(self):
self.display_name()
class Age(Animals):
def call_display_name(self):
self.display_age()
Name().call_display_name()

Categories