This question already has answers here:
Inheritance of private and protected methods in Python
(6 answers)
Closed 6 years ago.
When inheriting in python, i got following error with private variables:
AttributeError: 'dog' object has no attribute '_dog__name'
I searched a lot but didn't understand where my problem is;
class animal(object):
__name = ""
__height = ""
__weight = ""
__sound = ""
def __init__(self, name, height, weight, sound):
self.__name = name
self.__height = height
self.__weight = weight
self.__sound = sound
def toString(self):
return "{} is {} cm and {} weight and say {}.".format(self.__name, self.__height, self.__weight, self.__sound)
class dog(animal):
__owner = ""
def __init__(self, name, height, weight, sound, owner):
self.__owner = owner
super(dog, self).__init__(name, height, weight, sound)
def toString(self):
return "{} is {} cm and {} weight and say {} and belongs to {}.".format(self.__name, self.__height,
self.__weight, self.__sound,
self.__owner)
puppy = dog('puppy', 45, 15, 'bark', 'alex')
puppy.toString()
when you create var with double underscore, its just a notation use to indicate it as private variable, python do name mangling on the variable name itself to prevent normal way access to it.
However, its still not the real private variable like C/C++. You can still access the so called python "private var" with syntax below
var = __myvar
# access with _<class name>__myvar
From PEP,
_single_leading_underscore : weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an
underscore.
__double_leading_underscore : when naming a class attribute, invokes name mangling (inside class FooBar, __boo becomes _FooBar__boo
For your case, change your dog class toString method to below then it should works
def toString(self):
return "{} is {} cm and {} weight and say {} and belongs to {}.".format(self._animal__name, self._animal__height,
self._animal__weight, self._animal__sound,
self.__owner) # __owner remains because its not inherit from class animal
another option is to change your animal class variable to single underscore _ if you don't really need double underscore __
Related
Let's say I want to create a class 'House' that has some attributes of its own, but also has a (nested?) 'Resident' class which has some attributes and has a mandatory attribute 'surname'. A house instance may exist though without any residents. How can create this so that I can eventually do the following?
myhouse = House()
residentX = myhouse.resident('Smith')
Currently I set this up as a nested class but run into trouble when I try and initialise myhouse given that it is requiring a surname at this point for the nested Resident class (which I don't necessarily have at this point)
class House:
def __init__(self):
self.someattribute = <someattribute>
self.resident = self.Resident()
class Resident:
def __init__(self, surname):
self.surname = surname
I know I can restructure the code to not use nested classes and then explicitly tie any resident to a house in my code. However, I would like to use the dot notation here (myhouse.resident) to automatically tie a resident to a house.
Also, I understand that nested classes in python are somewhat frowned upon - I'm open to suggestions on how to do the above in a more pythonic manner.
I would break out the Resident class and use a property/setter for .resident
Like this:
class House:
def __init__(self):
self.someattribute = <someattribute>
self._resident = None
#property
def resident(self):
return self._resident
#resident.setter
def resident(self, surname):
r = Resident(surname)
self._resident = r
class Resident:
def __init__(self, surname):
self.surname = surname
However, if you want .resident to be callable but also want to track the house's residents, you can still break out the Resident class, and use:
class House:
def __init__(self):
self.someattribute = <someattribute>
self.residents = []
def resident(self, surname):
'''
Add a resident to the house
'''
r = Resident(surname)
self.residents.append(r)
return r
class Resident:
def __init__(self, surname):
self.surname = surname
When I run this code. I get the following errors
Traceback (most recent call last): File "C:/Users/Nabeel Hussain Syed/PycharmProjects/Hello World/check.py", line 80, in
print(spot.toString())
File "C:/Users/Nabeel Hussain Syed/PycharmProjects/Hello World/check.py", line 66, in toString
return "{} is {} cm tall and {} kilograms and say {}. His owner is {}".format(self.__name,
AttributeError: 'Dog' object has no attribute '_Dog__name'
Open the link of the image to check out the errors.
class Animal:
__name = None
__height = 0
__weight = 0
__sound = 0
def __init__(self, name, height, weight, sound):
self.__name = name
self.__height = height
self.__weight = weight
self.__sound = sound
def set_name(self, name):
self.__name = name
def set_height(self, height):
self.__height = height
def set_weight(self, weight):
self.__weight = weight
def set_sound(self, sound):
self.__sound = sound
def get_name(self):
return self.__name
def get_height(self):
return str(self.__height)
def get_weight(self):
return str(self.__weight)
def get_sound(self):
return self.__sound
def get_type(self):
print("Animal")
def toString(self):
return "{} is {} cm tall and {} kilograms and say {}".format(self.__name,
self.__height,
self.__weight,
self.__sound)
cat = Animal('Whiskers', 33, 10, 'Meow')
print(cat.toString())
class Dog(Animal):
__owner = ""
def __init__(self,name,height,weight,sound,owner):
self.__owner = owner
super(Dog,self).__init__(name,height,weight,sound)
def set_owner(self, owner):
self.__owner = owner
def get_owner(self):
return self.__owner
def get_type(self):
print("Dog")
def toString(self):
return "{} is {} cm tall and {} kilograms and say {}. His owner is {}".format(self.__name,
self.__height,
self.__weight,
self.__sound,
self.__owner)
def multiple_sounds(self, how_many=None):
if how_many is None:
print(self.get_sound())
else:
print(self.get_sound() * how_many)
spot = Dog("Spot", 53, 27, "Ruff", "Derek")
print(spot.toString())
Attributes with names starting with double underscores are considered "private", and not accessible from child classes. You could still access them by names like _Animal__name (Animal is a parent class name in which attribute was defined), but it's a bad practice.
More information in official documentation: https://docs.python.org/3.6/tutorial/classes.html#private-variables
the double-underscore has significance in Python. Please see this excerpt from a previous stack overflow answer:
Double leading underscore
This one actually has syntactical significance. Referring to
self.__var1 from within the scope of your class invokes name mangling.
From outside your class, the variable will appear to be at
self._YourClassName__var1 instead of self.__var1. Not everyone uses
this - we don't at all where I work - and for simple classes it feels
like a slightly absurd and irritating alternative to using a single
leading underscore.
However, there is a justification for it existing; if you're using
lots of inheritance, if you only use single leading underscores then
you don't have a way of indicating to somebody reading your code the
difference between 'private' and 'protected' variables - ones that
aren't even meant to be accessed by subclasses, and ones that
subclasses may access but that the outside world may not. Using a
single trailing underscore to mean 'protected' and a double underscore
to mean 'private' may therefore be a useful convention in this
situation (and the name mangling will allow a subclasses to use a
variable with the same name in their subclass without causing a
collision).
Just a quick question, so i have a class named animal and when you create the class you can initialise it with a dogName.
class animal:
def __init__(self, dogName):
self._owner = ""
self._address = ""
def setOwnerDetails(self, name, address):
self._owner = name
self._address = address
def getDetails(self):
return self._owner, self._address
def getName(self):
return self.dogName
##Does not work, trying to access constructor argument.
So when you initialise the instance with a value, which is dogName and in this instance the Dogname is Lucy, how can i access this value within a method?
I know i can do this by creating a instance variable but is there any other way i can do it. The variable above understandable does not work but is there any other way?
dog1 = animal("Lucy")
dog1.setOwnerDetails("Thomas", "35 Trop")
result = dog1.getDetails()
print(dog1.getName()) # trying to print the dog Name that is in the constructor argument.
Any help will be appreciated, I might not have explained it well.
You need to set dog_name as an instance attribute in the constructor:
def __init__(self, dog_name):
self._owner = ""
self._address = ""
self.dog_name = dog_name
You will then be able to access the attribute in the methods using self.dog_name.
Aside: as #jonrsharpe mentions in the comments, you should change your variable name from dogName to dog_name for PEP-8 compliance.
This question already has answers here:
Printing all instances of a class
(8 answers)
Closed 9 years ago.
I've been messing around in Python for about a month and a half at this point, and I was wondering: is there a way to print the values of one class variables for all objects in that class? e.g. (I was working on a mini-game kinda thing):
class potions:
def __init__(self, name, attribute, harmstat, cost):
self.name = name
self.attribute = attribute
self.harmstat = harmstat
self.cost = cost
Lightning = potions("Lightning Potion", "Fire", 15, 40.00)
Freeze = potions("Freezing Potion", "Ice", 20, 45.00)
I'd like to be able to print a list of all the names of the potions, but I couldn't find a way to do that.
If you have a list of all the potions it's simple:
potion_names = [p.name for p in list_of_potions]
If you don't have such a list, it is not so simple; you are better off maintaining such a list by adding potions to a list, or better still, a dictionary, explicitly.
You could use a dictionary to add potions to when creating instances of potions:
all_potions = {}
class potions:
def __init__(self, name, attribute, harmstat, cost):
self.name = name
self.attribute = attribute
self.harmstat = harmstat
self.cost = cost
all_potions[self.name] = self
Now you can always find all names:
all_potion_names = all_potions.keys()
and also look up potions by name:
all_potions['Freezing Potion']
You can use the garbage collector.
import gc
print [obj.name for obj in gc.get_objects() if isinstance(obj, potions)]
You could use a class attribute to hold references to all Potion instances:
class Potion(object):
all_potions = []
def __init__(self, name, attribute, harmstat, cost):
self.name = name
self.attribute = attribute
self.harmstat = harmstat
self.cost = cost
Potion.all_potions.append(self)
Then you can always access all the instances:
for potion in Potion.all_potions:
One of my classes does a lot of aggregate calculating on a collection of objects, then assigns an attribute and value appropriate to the specific object: I.e.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
class LeagueDetails(object):
def __init__(self): # added for clarity, corrected another typo
self.team_list = [Team('name'), ...]
self.calculate_league_standings() # added for clarity
def calculate_league_standings(self):
# calculate standings as a team_place_dict
for team in self.team_list:
team.place = team_place_dict[team.name] # a new team attribute
I know, as long as the calculate_league_standings has been run, every team has team.place. What I would like to be able to do is to scan the code for class Team(object) and read all the attributes, both created by class methods and also created by external methods which operate on class objects. I am getting a little sick of typing for p in dir(team): print p just to see what the attribute names are. I could define a bunch of blank attributes in the Team __init__. E.g.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
self.place = None # dummy attribute, but recognizable when the code is scanned
It seems redundant to have calculate_league_standings return team._place and then add
#property
def place(self): return self._place
I know I could comment a list of attributes at the top class Team, which is the obvious solution, but I feel like there has to be a best practice here, something pythonic and elegant here.
If I half understand your question, you want to keep track of which attributes of an instance have been added after initialization. If this is the case, you could use something like this:
#! /usr/bin/python3.2
def trackable (cls):
cls._tracked = {}
oSetter = cls.__setattr__
def setter (self, k, v):
try: self.initialized
except: return oSetter (self, k, v)
try: self.k
except:
if not self in self.__class__._tracked:
self.__class__._tracked [self] = []
self.__class__._tracked [self].append (k)
return oSetter (self, k, v)
cls.__setattr__ = setter
oInit = cls.__init__
def init (self, *args, **kwargs):
o = oInit (self, *args, **kwargs)
self.initialized = 42
return o
cls.__init__ = init
oGetter = cls.__getattribute__
def getter (self, k):
if k == 'tracked': return self.__class__._tracked [self]
return oGetter (self, k)
cls.__getattribute__ = getter
return cls
#trackable
class Team:
def __init__ (self, name, region):
self.name = name
self.region = region
#set name and region during initialization
t = Team ('A', 'EU')
#set rank and ELO outside (hence trackable)
#in your "aggregate" functions
t.rank = 4 # a new team attribute
t.ELO = 14 # a new team attribute
#see witch attributes have been created after initialization
print (t.tracked)
If I did not understand the question, please do specify which part I got wrong.
Due to Python's dynamic nature, I don't believe there is a general answer to your question. An attribute of an instance can be set in many ways, including pure assignment, setattr(), and writes to __dict__ . Writing a tool to statically analyze Python code and correctly determine all possible attributes of an class by analyzing all these methods would be very difficult.
In your specific case, as the programmer you know that class Team will have a place attribute in many instances, so you can decide to be explicit and write its constructor like so:
class Team(object):
def __init__(name ,place=None):
self.name = name
self.place = place
I would say there is no need to define a property of a simple attribute, unless you wanted side effects or derivations to happen at read or write time.