How do I call method .get_item(Example1()).do_something() in class Base from inside the class Example2?
class Base:
items = []
def add_item(self, item):
self.items.append(item)
def get_item(self, item):
return self.items[0]
class Item:
pass
class Example1(Item):
def do_something(self):
print('do_something()')
class Example2(Item):
def __init__(self):
'''
How call this method .get_item(Example1()).do_something() ?
'''
if __name__ == '__main__':
base = Base()
base.add_item(Example1())
base.add_item(Example2())
If you want such functionality, you need to pass Base to Example2 guy:
class Example2(Item):
def __init__(self, base):
self.base = base
self.base.get_item(Example1()).do_something()
# or if don't want to store base, and just call its method once:
base.get_item(Example1()).do_something()
if __name__ == '__main__':
base = Base()
base.add_item(Example1())
base.add_item(Example2(), base)
self.get_item(...)
or
Base.get_item(self, ...)
Related
class base():
def __init__(self):
self.var = 10
def add(self, num):
res = self.var+num
return res
class inherit(base):
def __init__(self, num=10):
x = super().add(num)
a = inherit()
print(a)
Hello,
I'm learning about inheritance and super(). When running this, the error AttributeError: 'inherit' object has no attribute 'var' is returned. How can I inherit the init variables too?
You first need to call super constructor because you did not define var in your base class constructor.
Working version of your code (though you should probably add var in base __init__)
class Base:
def __init__(self):
self.var = 10
def add(self, num):
res = self.var + num
return res
class Inherit(Base):
def __init__(self, num=10):
super().__init__()
x = super().add(num)
a = Inherit()
print(a)
one possible solution
class Base:
def __init__(self, var=10):
self.var = var
def add(self, num):
res = self.var + num
return res
class Inherit(Base):
pass
a = Inherit()
a.add(0) # replace 0 with any integer
I can't figure out the correct way to model this problem.
Here I give you a minimalistic version of my code:
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class AreaCalculator():
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
self.getArea()
class PerimeterCalculator():
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
AreaCalculator.__init__(self)
def getArea(self):
return area
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
PerimeterCalculator.__init__(self)
def getPerimeter(self):
return perimeter
a = TriangleAreaCalculator()
b = TrianglePerimeterCalculator()
Is there an elegant way to merge "TrianglePerimeterCalculator" and "TriangleAreaCalculator" classes into one, but keeping "PerimeterCalculator" and "AreaCalculator" separated?
[edit] As Kyle suggested in the comments, I can create a new class (let's call it "Triangle") that inherits from "PerimeterCalculator" and "AreaCalculator" at the same time, but what I want is to be able to tell a new instance of "Triangle" to behave as "PerimeterCalculator" or "AreaCalculator", but not both at the same time.
I think the "design pattern" you should use is multiple inheritance. Below is a modified version of your code demonstrating how do it (plus a few other changes to make it actually runnable and all classes new-style).
from abc import ABCMeta, abstractmethod
class AreaCalculator(object):
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
self.getArea()
class PerimeterCalculator(object):
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
super(TriangleAreaCalculator, self).__init__()
def getArea(self):
print('TriangleAreaCalculator.getArea() called on instance of {}'.format(
self.__class__.__name__))
# return area
return 13
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
super(TrianglePerimeterCalculator, self).__init__()
def getPerimeter(self):
print('TrianglePerimeterCalculator.getPerimeter() called on instance of {}'.format(
self.__class__.__name__))
# return perimeter
return 42
class MergedCalculator(TriangleAreaCalculator, TrianglePerimeterCalculator):
def __init__(self):
super(MergedCalculator, self).__init__()
merged = MergedCalculator()
print('merged.getArea() -> {}'.format(merged.getArea()))
print('merged.getPerimeter() -> {}'.format(merged.getPerimeter()))
Output:
TriangleAreaCalculator.getArea() called on instance of MergedCalculator
merged.getArea() -> 13
TrianglePerimeterCalculator.getPerimeter() called on instance of MergedCalculator
merged.getPerimeter() -> 42
Here's another answer, following the editing and clarification of your question. It allows creation of a single Triangle instance that can behave like either an AreaCalculator or PerimeterCalculator, as needed.
This programming pattern is called "delegation" and is used where the responsibility for implementing a particular operation is handed off to a different object—in this case an internally held instance of some other class. A common way to do this in Python is by overriding the class's default __getattr__() method.
Since you've never responded to the comment under my other answer about exactly what it is that controls which behavior is used, I added a set_behavior() method to allow it to be specified explicitly.
from abc import ABCMeta, abstractmethod
class AreaCalculator:
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
return self.getArea()
class PerimeterCalculator:
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
return self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
super(TriangleAreaCalculator, self).__init__()
def getArea(self):
print('TriangleAreaCalculator.getArea() called')
area = 13
return area
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
super(TrianglePerimeterCalculator, self).__init__()
def getPerimeter(self):
print('TrianglePerimeterCalculator.getPerimeter() called')
perimeter = 42
return perimeter
class Triangle:
def __init__(self):
delegate_classes = TriangleAreaCalculator, TrianglePerimeterCalculator
# Map delegate classes to instances of themselves.
self._delegates = {delegate_class: delegate_class()
for delegate_class in delegate_classes}
self.set_behavior(TriangleAreaCalculator) # Set default delegate.
def __getattr__(self, attrname):
# Called only for attributes not defined by this class (or its bases).
# Retrieve attribute from current behavior delegate class instance.
return getattr(self._behavior, attrname)
def set_behavior(self, delegate_class):
try:
self._behavior = self._delegates[delegate_class]
except KeyError:
raise TypeError("{} isn't a valid {} behavior delegate class"
.format(delegate_class, self.__class__.__name__))
if __name__ == '__main__':
triangle = Triangle()
# Uses instance's default behavior.
print('triangle.compute() -> {}'.format(triangle.compute()))
triangle.set_behavior(TrianglePerimeterCalculator) # Change behavior.
print('triangle.compute() -> {}'.format(triangle.compute()))
Output:
TriangleAreaCalculator.getArea() called
triangle.compute() -> 13
TrianglePerimeterCalculator.getPerimeter() called
triangle.compute() -> 42
I figured it out myself, with inspiration on the commentas/answers of Kyle and martineau.
I can create a merged class "Triangle" as follows:
class Triangle():
def __init__(self):
pass
def getTriangleArea(self):
print 'Triangle area'
def getTrianglePerimeter(self):
print 'Triangle perimeter'
And then modify TriangleAreaCalculator and TrianglePerimeterCalculator as follows:
class TriangleAreaCalculator(AreaCalculator, Triangle):
def __init__(self):
TriangleCalculator.__init__(self)
AreaCalculator.__init__(self)
def getArea(self):
super(TriangleAreaCalculator, self).getTriangleArea()
class TrianglePerimeterCalculator(PerimeterCalculator, Triangle):
def __init__(self):
TriangleCalculator.__init__(self)
PerimeterCalculator.__init__(self)
def getPerimeter(self):
super(TrianglePerimeterCalculator, self).getTrianglePerimeter()
This way, I can create a new Triangle-like instance that behaves as "PerimeterCalculator" or "AreaCalculator" (but not both at the same time):
a = TriangleAreaCalculator()
b = TrianglePerimeterCalculator()
a.compute() # correctly prints "Triangle area"
b.compute() # correctly prints "Triangle perimeter"
How to override an inherited class method, that needs to query for specific properties on the child class?
I'm not sure how to go about this. This is what I've got:
class base_class:
#classmethod
def a_method(cls, something):
return ndb.Query(kind=cls.__name__).fetch(keys_only=True)
#classmethod
def calls_a_method(cls, size=1, soemthing):
entity_keys = cls.a_method(something)
class child_class(base_class):
a_property = ndb.BooleanProperty()
def another_method():
stuff = child_class.calls_a_method() #?
How do I override a_method from the base_class, such that it will also filter out keys where a_property = False for the child_class?
I think that if you break up the query across the methods, you can construct a custom query in the child class:
class base_class:
#classmethod
def a_method(cls, something):
return ndb.Query(kind=cls.__name__)
#classmethod
def calls_a_method(cls, size=1, something):
entity_keys = cls.a_method(something).fetch(keys_only=True)
class child_class(base_class):
a_property = ndb.BooleanProperty()
#classmethod
def another_method(cls):
q = cls.a_method(something).filter(cls.a_property == False)
entity_keys = q.fetch(keys_only=True)
How about something like this?
class base_class(ndb.Model):
#classmethod
def a_method(cls, something):
return cls.Query().fetch(keys_only=True)
#classmethod
def calls_a_method(cls, something):
entity_keys = cls.a_method(something)
class child_class(base_class):
a_property = ndb.BooleanProperty()
#classmethod
def another_method(cls, value):
return cls.calls_a_method(value)
#classmethod
def a_method(cls, something):
return cls.query(cls.a_property==something).fetch(keys_only=True)
I am creating a subclass, but I am having difficulties making it inherit from the parent class:
def ParentClass(object):
def __init__(self,num):
self.num = num
self.get_soup()
def get_soup(self):
self.soup = 'soup'
return self.soup
def SubClass(Advert):
def __init__(self,num):
ParentClass.__init__(self,num)
def test(self):
print 'it works'
print self.num
if __name__== "__main__":
num = 1118868465
ad = SubClass(num)
ad.test()
Should I have a look at metaclasses?
You have functions in your code not classes, the parent class is also called ParentClass not Advert:
class ParentClass(object): # class not def
def __init__(self,num):
self.num = num
self.get_soup()
def get_soup(self):
self.soup = 'soup'
return self.soup
class SubClass(ParentClass): # inherit from ParentClass
def __init__(self, num):
super(SubClass, self).__init__(num)
def test(self):
print 'it works'
print self.num
You might want to have a read of this tutorial
What is a simple example of decorating a class by defining the decorator as a class?
I'm trying to achieve what has been implemented in Python 2.6 using PEP 3129 except using classes not functions as Bruce Eckel explains here.
The following works:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
def wrappedClass(*args):
return cls(*args)
return type("TestClass", (cls,), dict(newMethod=self.newMethod, classattr=self.arg))
def newMethod(self, value):
return value * 2
#Decorator("decorated class")
class TestClass(object):
def __init__(self):
self.name = "TestClass"
print "init %s"%self.name
def TestMethodInTestClass(self):
print "test method in test class"
def newMethod(self, value):
return value * 3
Except, in the above, wrappedClass is not a class, but a function manipulated to return a class type. I would like to write the same callable as follows:
def __call__(self, cls):
class wrappedClass(cls):
def __init__(self):
... some code here ...
return wrappedClass
How would this be done?
I'm not entirely sure what goes into """... some code here ..."""
If you want to overwrite new_method(), just do it:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
class Wrapped(cls):
classattr = self.arg
def new_method(self, value):
return value * 2
return Wrapped
#Decorator("decorated class")
class TestClass(object):
def new_method(self, value):
return value * 3
If you don't want to alter __init__(), you don't need to overwrite it.
After this, the class NormalClass becomes a ClassWrapper instance:
def decorator(decor_arg):
class ClassWrapper:
def __init__(self, cls):
self.other_class = cls
def __call__(self,*cls_ars):
other = self.other_class(*cls_ars)
other.field += decor_arg
return other
return ClassWrapper
#decorator(" is now decorated.")
class NormalClass:
def __init__(self, name):
self.field = name
def __repr__(self):
return str(self.field)
Test:
if __name__ == "__main__":
A = NormalClass('A');
B = NormalClass('B');
print A
print B
print NormalClass.__class__
Output:
A is now decorated. <br>
B is now decorated. <br>
\__main__.classWrapper