Access parent class method through child instance - python

I have the following code:
class Organ():
def __init__(self, organ_name, organ_weight):
self.organ_name = organ_name
self.organ_weight = organ_weight
def __repr__(self):
return "The {organ}'s weight is {weight}"\
.format(organ=self.organ_name, weight = self.organ_weight)
class Heart(Organ):
def __init__(self, heart_weight):
self.heart_weight_grams = heart_weight
super().__init__(__class__.__name__, self.heart_weight_grams)
def __repr__(self):
return "My heart's weight is {weight} grams"\
.format(weight=self.heart_weight_grams)
my_heart = Heart(200)
print(my_heart) #returns "My heart's weight is 200 grams"
From my child instance my_heart, how do I access the parent class method __repr__() method?

To access the parent from child use super(), ie : super().__repr__() but here you don't need it, in fact you may not use heart_weight_grams attribut, because it's the same as organ_weight in the parent
If you have more attributs into Heart class, you can call __repr__ parent and concat more info from the child class
class Organ:
def __init__(self, organ_name, organ_weight):
self.organ_name = organ_name
self.organ_weight = organ_weight
def __repr__(self):
return "The {organ}'s weight is {weight}".format(organ=self.organ_name, weight=self.organ_weight)
# return f"The {self.organ_name}'s weight is {self.organ_weight}" # shorter
class Heart(Organ):
def __init__(self, heart_weight, hearbeat=60):
super(Heart, self).__init__("heart", heart_weight)
self.hearbeat = hearbeat
def __repr__(self):
return super().__repr__() + f" and beats at {self.hearbeat}"
my_heart = Heart(200)
print(my_heart) # The Heart's weight is 200

When you inherit a class, you can access parent functions using super. Just use super().__repr__() to access the function.

Related

Prevent user of changing variable type in python

I have main class with a lot of attributes that are initially defined as an object of a Prop class. This Prop class has two attributes: its value and the options, which is a list of acceptable values for the attribute.
class Prop():
def __init__(self, value, *options):
self.value = value
self.options = options
class Main():
def __init__(self):
self._prop1 = Prop(None)
self._prop2 = Prop(None)
The first important thing here is that _propx has to be an instance variable, since I will create more than one instance of Main.
The values of a Prop instance can either be a string or an integer, but the problem with this code is that I have to be sure that the user will do something like main._prop1.value = 1 and not main._prop1 = 1 otherwise it would break my code when doing _prop1.options. I don't want to use traits, thus I decided to make each _propx instance a kind of property, but I'm talking about a lot of instances and I don't want to define each setter especially because they will be all the same.
I found two solutions to solve this problem, the first is by using the same setter to all properties:
class Main():
def __init__(self):
self._prop1 = Prop(None)
self._prop2 = Prop(None)
def set_prop(attr):
def set_value(self, value):
self.__dict__[attr].value = value
return set_value
prop1 = property(fset=set_prop('_prop1'))
prop2 = property(fset=set_prop('_prop2'))
The second is by using an auxiliary class and redefine its __set__:
class Aux():
def __set_name__(self, owner, name):
self.public_name = name
self.private_name = '_' + name
def __set__(self, obj, value):
print(self, obj, value, self.private_name)
obj.__dict__[self.private_name].value = value
class Main():
def __init__(self):
self._prop1 = Prop(None)
self._prop2 = Prop(None)
prop1 = Aux()
prop2 = Aux()
the first on seems cleaner, but I have to pass the private name of each variable and I have to write the setter in the Main which I don't like because I would it to be as clean as possible. By other hand, in the second I have to use an auxiliary class.
My question is: is there a way of defining the setter in the Prop class? The reason why I couldn't find a way of doing this is that the Aux.__set__ seems to work only when I create an Aux instance as a class variable (static variable). This is also why I have to create a private and a public variable for each property. Is there a way of using __set__ to an instance (non-static) variable?

Get a dict of all properties of self without including child class properties

Say I have the following two classes:
class PlayerState:
def __init__(self):
self.someStateProp = 10
# get the state of this class only as a dict
def getState(self):
return {name: attr for name, attr in self.__dict__.items()
if not name.startswith("__")
and not callable(attr)
and not type(attr) is staticmethod}
class Player(PlayerState):
def __init__(self):
super().__init__()
self.someNonStateProp = 'foo'
player = Player()
print(player.getState())
# someNonStateProp should not be shown
>> {'someStateProp': 10, 'someNonStateProp': 'foo'}
The method PlayerState.getState as it stands is able to return a dict containing all attributes of itself, excluding constructors and methods. I want to expand on it and make it also only return the direct properties of PlayerState, and not Player.
Edit: Using self.__class__.__dict__.items() instead of self.__dict__.items() just gives me all the methods of Player.
You provide no way to really differentiate between state and non-state attributes. If the object is mutable and has a mutable dict, there is really no way to determine who set the value for a particular attribute. There will be cases where children will want to add to the state. If the state is something special, keep it as a separate dictionary instead of filtering every time:
class PlayerState:
def __init__(self):
self.state = {}
self.state['someProp'] = 10
# get the state of this class only as a dict
def getState(self):
return self.state
class Player(PlayerState):
def __init__(self):
super().__init__()
self.someNonStateProp = 'foo'
self.state['otherProp'] = 'bar'
If it bothers you that you can't access state elements through normal dot access, add some properties to your class:
#property
def someStateProp(self):
return self.state['someProp']
Alternatively, hard-code a list of the names you want.
class PlayerState:
states = ['someStateProp']
def __init__(self):
self.someStateProp = 10
# get the state of this class only as a dict
def getState(self):
return {name: getattr(self, name) for name in self.names}
class Player(PlayerState):
names = PlayerState.names + ['otherStateProp']
def __init__(self):
super().__init__()
self.someNonStateProp = 'foo'

Unable to access the parent class member in base class in python

I am using python 3.4 and i am new in object oriented programming and want to access the parent class member in my child class. But it is not accessible. Can anyone help me to get rid of this?
# Base class members can be accessed in
# derived class using base class name.
# Parent or super class
class Company:
def BasicInfo(self):
self.CompanyName = "ABC Solutions"
self.Address = "XYZ"
# Inherited or child class
class Employee(Company):
# constructor
def __init__(self, Name):
print("Employee Name:", Name)
print("Company Name:", self.CompanyName)
def main():
# Create an object
emp01 = Employee("John")
if __name__ == "__main__":
main()
The below mentioned code is working but using the same concept, my code is not working, why? Can anyone explain me the reason.
class Room:
def __init__(self):
self.roomno = 0
self.rcap = 0
self.rooms = {}
self.nog = 10
def addRoom(self):
self.rcap = input("Please enter room capacity:\n")
self.rooms[self.roomno] = self.rcap
class Booking(Room):
def addBooking(self):
while int(self.nog) > int(self.rcap):
print("Guest count exceeds room capacity of: %d" % int(self.rcap))
x = Booking()
x.addRoom()
x.addBooking()
You're missing a call to the superclass' BasicInfo method:
def __init__(self, Name):
print("Employee Name:", Name)
super().BasicInfo()
# ^^Here^^
print("Company Name:", self.CompanyName)
You can replace super().BasicInfo() with a direct reference to the class obviously:
Company.BasicInfo(self)
In your second example, the subclass does not define a __init__ method, so it would inherit that from parent; as a result, the instance variables would be present in the child class.
Your base class method BasicInfo is never getting called. If you call it explicitly either in your child class's __init__, it would work
class Employee(Company):
# constructor
def __init__(self, Name):
super(Employee, self).BasicInfo()
print("Employee Name:", Name)
print("Company Name:", self.CompanyName)

What is the order of namespaces in inheritance?

A derived class has access to its base class member functions implicitly, unless I am mistaken. A derived class can also access its base class' attributes by prefixing a call to them like this: BaseClass.base_attribute. But I seemingly do not understand how instances of a derived class can use the methods of the base class. Example:
class Visitor():
""" Interface to Visitor
provide an interface to visitors that
perform an operation on a data collection """
def visitProduce():
pass
def visitMeat():
pass
def visitBakedGoods():
pass
def visitDairy():
pass
def visitNonFood():
pass
class PriceVisitor(Visitor):
__cost = 0.0 # total cost of groceries
def __init__(self):
self.__cost = 0.0
def visitProduce(self, p):
self.__cost += p.price()
def visitMeat(self, m):
self.__cost += m.price()
def visitBakedGoods(self, b):
self.__cost += b.price()
def visitDairy(self, d):
self.__cost += d.price()
def visitNonFood(self, nf):
self.__cost += nf.price()
class Groceries():
shopping_cart = [] # list of grocery items
def Groceries(self):
self.shopping_cart = []
def addProduce(self, p):
pass
def addMeat(self, m, lb):
pass
def addBakedGoods(self, b):
pass
def addDairy(self, d):
pass
def addNonFood(self, nf):
pass
def accept(self, v):
pass
def getShoppingCart(self):
print(self.shopping_cart)
def calculateCost(self, v):
for item in self.shopping_cart:
item.accept(v)
item.details()
print('Total cost is: $', v.__cost)
class Produce(Groceries):
def addProduce(self):
Groceries.shopping_cart.append(self)
def accept(self, v):
v.visitProduce(self)
def price(self):
return self.__price
def details(self):
print(self.__name, ' for: $', self.__price + '')
class Apples(Produce):
__name = None
__price = 3.25
def __init__(self, name):
self.__name = name
And here is a test of the Apple, Produce, Groceries, and PriceVisitor classes
import VisitorPattern as vp
def main():
# Visitor object
my_visitor = vp.PriceVisitor()
# Grocery object stores objects in its shopping_cart attribute
my_groceries = vp.Groceries()
# Add items
red_apple = vp.Apples('red apple')
gold_apple = vp.Apples('gold apple')
red_apple.addProduce()
gold_apple.addProduce()
my_groceries.getShoppingCart()
my_groceries.calculateCost(my_visitor)
if __name__ == '__main__':
main()
Now, the way I understand it is that upon the construction of the instance of Apple, it has access to Produce's method price(). Calling this method with an instance of the Apple class will then pass its own instance in place of the 'self'. The program then returns the value of the __price attribute belonging to the instance calling the method, in this case Apple. However, I get this error:
C:\Users\josep_000\Documents\School\Summer 2015\Python Assignment 4>python test.
py
[<VisitorPattern.Apples object at 0x026E0830>, <VisitorPattern.Apples object at
0x026E0910>]
Traceback (most recent call last):
File "test.py", line 23, in <module>
main()
File "test.py", line 20, in main
my_groceries.calculateCost(my_visitor)
File "C:\Users\josep_000\Documents\School\Summer 2015\Python Assignment 4\Visi
torPattern.py", line 60, in calculateCost
item.accept(v)
File "C:\Users\josep_000\Documents\School\Summer 2015\Python Assignment 4\Visi
torPattern.py", line 71, in accept
v.visitProduce(self)
File "C:\Users\josep_000\Documents\School\Summer 2015\Python Assignment 4\Visi
torPattern.py", line 28, in visitProduce
self.__cost += p.price()
File "C:\Users\josep_000\Documents\School\Summer 2015\Python Assignment 4\Visi
torPattern.py", line 74, in price
return self.__price
AttributeError: 'Apples' object has no attribute '_Produce__price'
How does the binding and namespaces actually work in inheritance? I could just write the price() method in each of Produce's derived classes, but that would defeat the point of inheritance. I think my problem also stems from name mangling, but still don't know what happens if I don't make my attributes 'private'. Clarification would be great. Thanks
Edit
I declared the constructor of Groceries wrong:
# Wrong way
def Groceries(self):
self.shopping_cart = []
# Should be
def __init__(self):
self.__shopping_cart = []
The product of a full time job and homework in the evening
What is the order of namespaces in inheritance?
Python uses the Method Resolution Order to find the method bound to that instance of the object.
It also invokes name mangling, which is why you can't find the method, _Produce__price. You're trying to use .__price but when it is inherited, Python adds the name of the class to the front of the name. Don't use two underscores, change the two underscores to one, and your code will work as you expect, and you'll consistently look up ._price which won't invoke the name mangling.
See the docs for more on this:
https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
Not really a direct answer to all your questions but I hope the following code sheds some light on how to do inheritance in Python.
class Produce(object):
def __init__(self, name=None, price=None):
self.__name = name
self.__price = price
def __str__(self):
return self.__name
#property
def bulk_price(self):
return self.__price * 100
class Apple(Produce):
def __init__(self, name="Apple"):
self.__name = name
self.__price = 3.25
super(self.__class__, self).__init__(self.__name, self.__price)
a = Apple("Gold Apple")
print a
print a.bulk_price
# Gold Apple
# 325.0
As you can see, I made name and price inaccessible in both classes. This way, I cannot just call them explicitly, i.e. a.__price. By using super as well in the child class, I am able to avoid referring to the base class further while still having access to its methods.
I have saw your error, your parent need to call child's function, but you have not transferred child to parent, so it will get the errors.Now I give my example:
class A:
def __init__(self, handler):
self.a = 5
self.real_handler = handler
def get(self):
print "value a = %d"%self.a
self.real_handler.put()
class B(A):
def __init__(self):
A.__init__(self, self) ##transport B to A
self.b = 3
def get(self):
print "value b is %d"%self.b
A.get(self)
def put(self):
self.b = 6
print "value b change into %d"%self.b
if __name__=="__main__":
b = B()
b.get()
In parent B, it will call the child A's fuction put(). I hope this can help you.

Python AttributeError: property cannot overwrite inherited attribute?

I still don't fully understand when and how to use properties. Here I have a class SpecialCar which is inheriting Car. The variable summer_tire should basically be equivalent to tire, except for the name. So whenever I am asking for either of those two, I want to get summer_tire.
Using #property results in an error. Deleting the #property line will print 0, but I want to get 2.
class Car():
def __init__(self):
self.tire = 0
class SpecialCar(Car):
def __init__(self):
Car.__init__(self)
self.summer_tire = 2
self.winter_tire = 5
#property
def tire(self):
return self.summer_tire
i = SpecialCar()
print(i.tire)
You declared a property that doesn't have a setter, thus self.tire = 0 in Car.__init__ fails.
You could give your new property a setter:
class SpecialCar(Car):
def __init__(self):
Car.__init__(self)
self.summer_tire = 2
self.winter_tire = 5
#property
def tire(self):
return self.summer_tire
#tire.setter
def tire(self, new_tire):
self.summer_tire = new_tire
or you could avoid calling Car.__init__ altogether, or make Car.tire a class attribute, set as part of the class and replaced with the property in subclasses.

Categories

Resources