将要覆盖的实现方法分开是pythonic吗?

Posted

技术标签:

【中文标题】将要覆盖的实现方法分开是pythonic吗?【英文标题】:Is it pythonic to separate implementation method to be overridden? 【发布时间】:2013-11-24 20:19:10 【问题描述】:

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

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

但我关心的是它是否在 python 上可接受,因为根据我的经验,我从未见过这样的代码。

正常多态性

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

【问题讨论】:

我不是说它是或不是,但是给被覆盖的方法一个“私有”前导下划线名称绝对是很奇怪的。 在 Python 中,通常由 API 的 消费者 来获取正确的参数。如果消费者想给你一个 scale 这是一个元组,那就这样吧,那是他们的头,不是你的。 我不知道它是不是pythonic...不是说实现是不是pythonic;正如martijn所说,只是python程序员不倾向于这种严谨性。在 C 等语言中你不需要它,因为你有静态类型检查。它肯定会对性能产生重大影响。 【参考方案1】:

除了您描述的之外,还有我看到的替代方案:

    使用“实现方法分离”技术,但给它一个更友好的名称(没有下划线,可能是一个可以将它与get_area_from_validated_scale 等公共 API 区分开来的名称)。我在我的项目中使用了这种技术。 执行“实现方法分离”技术,用户覆盖该方法但调用进行验证的基类方法。 (不过,如果您需要验证输入和输出,则会变得更加复杂。) 在基类上创建 2 个方法 get_area_validate_inputget_area_validate_output,并要求实现者在每次实现 get_area 时调用它们。 #2 和 #3 的变体,但使用装饰器完成,因此实现者只需将 @area_validation 放在其方法定义之上。

【讨论】:

以上是关于将要覆盖的实现方法分开是pythonic吗?的主要内容,如果未能解决你的问题,请参考以下文章

Python 字符串连接方式有这么种,你知道吗?

python实现系统公网和私网流量监控

快速排序方法——python实现

Python 单元测试在哪里? [关闭]

Python最常用的函数基础语句有哪些?你都知道吗

文件内容操作