2013-08-16 45 views
1

我正在使用繼承的面向對象方法來解決問題,我想知道如何將「鴨打字」原則應用於此問題。如何有效地繼承使用鴨打字

我有一個類BoxOfShapes這將與ShapesCircleSquareRectangle)名單中實例化

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 

所以讓我們看看BoxOfShapes__repr__()方法。據我瞭解,鴨打字的實施會是這樣的,

def __repr__(self): 
    return str(self.elements) 

因爲這樣說:「我不在乎我有什麼樣的元素,只要它們實現__str__()__repr__()。這個輸出是

>>> print myBox 
[Rectangle, 10 x 13;, Rectangle, 9 x 5;, Circle, radius 12;, Circle, radius 8;, Circle, radius 36;, Square, 10 x 10;] 

可以說,我想從BoxOfShapes更可讀的輸出 - 我知道所有的形狀是某些類型的,所以這將是很好的分類,他們就像這樣:

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

這樣做的輸出,

>>> print myBox 
Box of Shapes; Circles: ['radius 12', 'radius 8', 'radius 36'], Squares: ['10 x 10'], Rectangles: ['10 x 13', '9 x 5']; 

哪一個更容易閱讀,但我不再使用鴨打字,現在我不得不改變我的BoxOfShapes定義每當我想到一種新的形狀。

我的問題是(如何)將這種情況下應用鴨子打字?

+0

'__repr__'應該是不太模糊,你正在使用。特別是,它應該使用元素「__repr__」,它應該可能顯示元素的順序。要嘗試的一件好事是製作'eval(repr(thing))== thing',或者儘可能地接近你的想法。我推薦'返回'BoxOfShapes({})'。格式(repr(self.elements))' – user2357112

+0

如果你想要一些漂亮而且容易理解的東西,那就是'__str__'的用途。 – user2357112

+2

與那些'type()'靜態方法有什麼關係?你應該可能會失去它們。如果你需要一個對象類型的名字,那麼就有內建的'type()'函數和類型的__name__'屬性(並且通常不用,你可以使用類型對象而不是用名字來混淆) )。 – delnan

回答

1

這是不是真正的鴨打字,但關於繼承一般(你可以問究竟對Java同樣的問題,它沒有鴨子類型的概念,例如)。

你想要做的只是創建一個字典映射類型到實例列表。這很容易做到這一點動態:

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()) 
1

您已經爲有效使用繼承鋪平了道路。您爲每個形狀定義一個type方法。只需創建一個字典,將該類型映射到您的BoxOfShapes實現中該類型的元素列表。

正如其他人所建議的,使用內置的type()函數。如果需要形狀名稱的字符串表示,請使用單獨的實例方法。

1

這是一個解決方案

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

這似乎並不理想,但。

更合適repr可能只是返回self.elementslen

def __repr__(self): 
    return "<%s, length=%s>" % (type(self).__name__, len(self.elements))