【发布时间】:2016-10-06 04:37:54
【问题描述】:
我不清楚使用旨在被覆盖的静态方法设计类的最佳方法是什么。我会尝试用一个例子来解释。
我们有一个类Goat 和一个方法can_climb。 (顺便说一下,这是 Python 3,在 Python 2 中我会写 class Goat(object):。)
class Goat:
def __init__(self, *args):
...
def can_climb(self, mountain):
return mountain.steepness < 10
billy = Goat("Billy")
if billy.can_climb(mount_everest):
print("wow Billy, impressive")
这按预期工作,但方法can_climb 不使用self。将其设为静态方法似乎更简洁,pylint 甚至对上述方法发出警告。所以让我们改变一下:
class Goat:
def __init__(self, *args):
...
@staticmethod
def can_climb(mountain):
return mountain.steepness < 10
billy = Goat("Billy")
if billy.can_climb(mount_everest):
print("wow Billy, impressive")
接近结尾的billy.can_climb 可以改为Goat.can_climb,在这个例子中不会有什么不同。有些人甚至可能认为通过类而不是实例调用静态方法更清晰、更直接。
但是,当我们使用继承和引入多态时,这会导致一个微妙的错误:
class Goat:
def __init__(self, *args):
...
@staticmethod
def can_climb(mountain):
return mountain.steepness < 10
class MountaineeringGoat(Goat):
@staticmethod
def can_climb(mountain):
return True
billy = get_ourselves_a_goat_called_billy()
if Goat.can_climb(mount_everest): # bug
print("wow Billy, impressive")
调用Goat.can_climb 的代码知道billy 是Goat 的一个实例,并错误地假设它的类型是Goat,而实际上它可能是Goat 的任何子类型。或者它错误地假设子类不会覆盖静态方法。
在我看来,这似乎是一个容易犯的错误;可能Goat 在引入这个bug 的时候没有任何子类,所以没有注意到这个bug。
我们如何设计和记录一个类以避免这种错误?特别是,此示例中的 can_climb 应该是静态方法还是应该使用其他方法?
【问题讨论】:
-
您已经演示了如何避免该错误;除非您需要特定的类,否则请在实例上调用方法(和属性)。并进行单元测试来检测功能回归。
-
我还不相信我的设计是最好的设计。也许我真的应该使用实例方法?
-
@jonrsharpe 如果可能的话,我正在寻找从班级方面而不是调用方方面避免此问题的方法。
-
你不能,如果调用者明确选择了类,那就是(并且应该!)被调用,没有什么可修复的。即使您将其设为实例方法,调用者仍然可以执行
Goat.can_climb(billy, ...)。至于“最佳设计”,很难用一个抽象的例子来说明,至少部分基于意见。
标签: python inheritance polymorphism static-methods