是否pythonic分离实现方法被覆盖?

时间:2013-11-12 15:34:53

标签: python oop polymorphism abstract-class abstract-methods

我发现将抽象方法分成两个方法似乎很有用,一个用于公共接口,另一个用于子类重写。

通过这种方式,您可以为输入和输出添加前置条件/​​后置条件检查,从而可以抵御人为错误。

但我关注的是它是否可以接受,因为在我的小经验中,我从未见过像这样的代码。

正常多态

import abc

class Shape:
    """Abstract base class for shapes"""
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def get_area(self, scale):
        """Calculates the area of the shape, scaled by a factor.
        Do not blame for a silly example.
        """
        pass

class Rectangle(Shape):
    def __init__(self, left, top, width, height):
        self.left = left
        self.top = top
        self.width = width
        self.height = height

    def get_area(self, scale):
        return scale * self.width * self.height

print(Rectangle(10, 10, 40, 40).get_area(3))

# Gosh!... gets tons of 3's
print(Rectangle(10, 10, 40, 40).get_area((3,)))

实施方法已分开

import abc

class Shape:
    """Abstract base class for shapes"""
    __metaclass__ = abc.ABCMeta

    def get_area(self, scale):
        """Calculates the area of the shape, scaled by a factor"""

        # preconditions
        assert isinstance(scale, (int,float))
        assert scale > 0

        ret = self._get_area_impl(scale)

        # postconditions
        assert isinstance(ret, (int,float))
        assert ret > 0

        return ret

    @abc.abstractmethod
    def _get_area_impl(self, scale):
        """To be overridden"""
        pass

class Rectangle(Shape):
    def __init__(self, left, top, width, height):
        self.left = left
        self.top = top
        self.width = width
        self.height = height

    def _get_area_impl(self, scale):
        return scale * self.width * self.height

print(Rectangle(10, 10, 40, 40).get_area(3))
print(Rectangle(10, 10, 40, 40).get_area((3,))) # Assertion fails

1 个答案:

答案 0 :(得分:0)

除了您描述的内容之外,以下是我看到的替代方案:

  1. 使用“实现方法分离”技术,但给它一个更友好的名称(没有下划线,可能是一个区别于公共API的名称,如get_area_from_validated_scale)。我在我的项目中使用这种技术。
  2. 执行“实现方法分离”技术,其中用户重写方法但调用执行验证的基类方法。 (但是,如果需要验证输入和输出,则会变得更复杂。)
  3. 在基类get_area_validate_inputget_area_validate_output上创建2个方法,并要求实施者在每次实施get_area时调用这些方法。
  4. #2和#3的变化,但是使用装饰器完成,因此实现者只需要将@area_validation放在方法定义之上。