flo*_*ake 7 python polymorphism inheritance static-methods
我不清楚使用静态方法设计类的最佳方法是什么,这些方法可以覆盖.我将尝试用一个例子来解释.
我们有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")
Run Code Online (Sandbox Code Playgroud)
这按预期工作,但该方法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")
Run Code Online (Sandbox Code Playgroud)
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")
Run Code Online (Sandbox Code Playgroud)
调用的代码Goat.can_climb知道它billy是一个实例,Goat并且Goat当它确实是任何子类型时,会做出错误的假设,即它的类型Goat.或者它可能错误地假定子类不会覆盖静态方法.
在我看来,这似乎是一个容易犯的错误; 也许Goat在引入这个bug的时候没有任何子类,所以没有注意到这个bug.
我们如何设计和记录一个类,以避免这种错误?特别是,can_climb从这个例子中应该是静态方法还是应该使用其他东西呢?
小智 13
继承显然意味着对基类的了解.@staticmethod不知道它所附属的那个阶级(因此他们早些时候 - 不是现在 - 称它为'未绑定的';现在技术上@staticmethod根本不是一种方法;它是一种功能.
但是@classmethod完全了解它附属的课程; 它在技术上不是一种功能,而是一种方法.
为什么@staticmethod呢?它在派生类中继承,但如前所述,不知道基类; 我们可以"使用它",就像我们在派生类中定义它一样.
从技术上讲,@classmethods 'bounded';@staticmethod不是.
曾有人问我,我会建议名称@staticfunction为@staticmethod.
实际上,至少在 Python 3.8 中,我确实看到billy.can_climb了和之间的区别,Goat.can_climb并且据我所知,代码并没有错误地假设 的类型billy是Goat:
class Mountain:
def __init__(self, steepness):
self.steepness = steepness
class Goat:
@staticmethod
def can_climb(mountain):
return mountain.steepness < 10
class MountaineeringGoat(Goat):
@staticmethod
def can_climb(mountain):
return True
def get_ourselves_a_goat_called_billy():
return MountaineeringGoat()
mount_everest = Mountain(100)
billy = get_ourselves_a_goat_called_billy()
if billy.can_climb(mount_everest):
print("wow Billy, impressive")
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,billy.can_climb(mount_everest)实际上调用了MountaineeringGoat.can_climb(mount_everest)并且我确实看到了这个输出:
wow Billy, impressive。
| 归档时间: |
|
| 查看次数: |
6989 次 |
| 最近记录: |