I'm using an object-oriented approach with inheritance to solve a problem, and I'm wondering how to apply 'Duck Typing' principles to this problem.
I have a class BoxOfShapes
which would be instantiated with a list of Shapes
( Circle
, Square
and Rectangle
)
import numpy as np
class Shape(object):
def __init__(self,area):
self.area = area;
def dimStr(self):
return 'area: %s' % str(self.area)
def __repr__(self):
return '%s, %s' % (self.__class__.__name__, self.dimStr()) + ';'
class Circle(Shape):
def __init__(self,radius):
self.radius = radius
def dimStr(self):
return 'radius %s' % str(self.radius)
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def dimStr(self):
return '%s x %s' % (str(self.width), str(self.height))
class Square(Rectangle):
def __init__(self, side):
self.width = side
self.height = side
class BoxOfShapes(object):
def __init__(self, elements):
self.elements = elements
def __repr__(self):
pass
listOfShapes = [Rectangle(10,13),Rectangle(9,5),Circle(12),Circle(8),Circle(36),Square(10)]
myBox = BoxOfShapes(listOfShapes)
print myBox
So lets look at the __repr__()
method of BoxOfShapes
. From what I understand, a duck-typing implementation would be something like,
def __repr__(self):
return str(self.elements)
because this says 'I don't care what elements I have as long as they implement __str__()
or __repr__()
. The output of this is
>>> print myBox
[Rectangle, 10 x 13;, Rectangle, 9 x 5;, Circle, radius 12;, Circle, radius 8;, Circle, radius 36;, Square, 10 x 10;]
Lets say I want a more human-readable output from BoxOfShapes
- I know all the shapes are of certain types, so it would be nice to categorize, them like so:
def __repr__(self):
circles = [ el.dimStr() for el in self.elements if isinstance(el, Circle)]
squares = [ el.dimStr() for el in self.elements if isinstance(el, Square)]
rectangles = [el.dimStr() for el in self.elements if (isinstance(el, Rectangle) and not isinstance(el, Square)) ]
return 'Box of Shapes; Circles: %s, Squares: %s, Rectangles: %s;' % ( str(circles), str(squares), str(rectangles))
The output of this is,
>>> print myBox
Box of Shapes; Circles: ['radius 12', 'radius 8', 'radius 36'], Squares: ['10 x 10'], Rectangles: ['10 x 13', '9 x 5'];
which is easier to read, but I am no longer using duck-typing and now I have to change my definition of BoxOfShapes
any time I think up a new kind of shape.
My question is (how) would one apply duck-typing in this kind of scenario?
You've already paved the way to use inheritance effectively. You define a type
method for each shape. Simply create a dictionary that maps the type to a list of elements of that type in your BoxOfShapes
implementation.
As others have suggested, use the built-in type()
function. If you want a string representation of the name of the shape, use a separate instance method.
This is one solution
from collections import defaultdict
class BoxOfShapes(object):
def __init__(self, elements):
self.elements = elements
self.groupings = defaultdict(list)
for element in elements:
self.groupings[type(element)].append(element)
def __repr__(self):
return "Box of Shapes: %s;" % ", ".join(type(group[0]).__name__ + "s: " + str(group) for group in self.groupings.itervalues())
This doesn't seem ideal though.
A more suitable repr
might just to be to return the len
of self.elements
.
def __repr__(self):
return "<%s, length=%s>" % (type(self).__name__, len(self.elements))
This isn't really about duck typing, but about inheritance generally (you could ask exactly the same question about Java, which has no concept of duck typing, for example).
What you want to do is simply to create a dictionary mapping types to list of instances. It's fairly easy to do that dynamically:
from collections import defaultdict
type_dict = defaultdict(list)
for element in self.elements:
type_dict[element.type()].append(element.dimStr())
return ','.join('%s: %s' for k, v in type_dict.items())
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.