【问题标题】:How to use duck typing effectively with inheritance如何通过继承有效地使用鸭子类型
【发布时间】:2013-08-16 21:25:12
【问题描述】:

我正在使用带有继承的面向对象的方法来解决问题,我想知道如何将“Duck Typing”原则应用于这个问题。

我有一个 BoxOfShapes 类,它将使用 Shapes 列表(CircleSquareRectangle)进行实例化

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 的定义,只要我想出一种新的形状。

我的问题是(如何)在这种情况下应用鸭子打字?

【问题讨论】:

  • __repr__ 应该比您使用的要少得多。特别是,它应该使用元素的__repr__,并且它可能应该显示元素的顺序。尝试的一件好事是制作eval(repr(thing)) == thing,或者尽可能接近。我推荐return 'BoxOfShapes({})'.format(repr(self.elements))
  • 如果你想要一些漂亮且易于阅读的东西,这就是__str__ 的用途。
  • 那些type() 静态方法是怎么回事?你可能应该失去它们。如果您需要对象类型的名称,可以使用内置的type() 函数和类型的__name__ 属性(通常,您可以只使用类型对象而不是胡乱使用它的名称)。
  • 而且你不能很容易地访问实例的staticmethods,你最好将类型作为类的普通属性。
  • @AnjoMan: Container objects'__str__ 使用元素'__repr__,因为['3', 3, 'a, b', ''][3, 3, a, b, ] 更具人类可读性。

标签: python oop duck-typing


【解决方案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())

【讨论】:

    【解决方案2】:

    您已经为有效使用继承铺平了道路。您为每个形状定义一个type 方法。只需创建一个字典,将类型映射到您的 BoxOfShapes 实现中的该类型的元素列表。

    正如其他人建议的那样,使用内置的type() 函数。如果您想要形状名称的字符串表示,请使用单独的实例方法。

    【讨论】:

      【解决方案3】:

      这是一种解决方案

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

      【讨论】:

        猜你喜欢
        • 2014-05-22
        • 2011-03-20
        • 2016-02-09
        • 2018-11-06
        • 2020-05-01
        • 1970-01-01
        • 2011-12-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多