2013-01-21 8 views
1

比方说,我们有以下类别:这种将鸭子打字与isinstance()混合在一起的方法是否合理?

class Duck(object): 
    pass 

class OldFashionedDuck(Organism, Duck): 
    def look(self): 
     self.display_biological_appearance() 
    def walk(self): 
     self.keep_balance_on_two_feet() 
    def quack(self): 
     self.make_noise_with_lungs("Quack!") 

class ArtificialDuck(Robot, Duck): 
    def look(self): 
     self.display_imitation_biological_appearance() 
    def walk(self): 
     self.engage_leg_clockwork() 
    def quack(self): 
     self.play_sound("quack.au") 

在这个例子中,OldFashionedDuck和ArtificialDuck没有共同的实现,而是通过建设他们都将用于isinstance(...,鸭)返回True。

这并不完美,但它是我认为可能有助于尊重鸭子打字和(通过空的mixin继承)allow isinstance()的东西。实质上,它提供了一个契约来满足一个接口,所以它不是基于完成所有工作的类来调用isinstance(),而是基于任何人都可以选择的接口。

我看过基于“isinstance()被认为有害的文章”,因为它打破了鸭子的打字。然而,至少我作为一个程序员想知道,如果不一定是一个对象从哪里获取函数,但是它是否实现了一个接口。

这种方法是否有用,如果有的话可以改进?

+1

您不清楚如何或为什么要使用'isinstance()'。这使得很难解决这是否是正确的事情。 –

+0

[抽象基类](http://www.python.org/dev/peps/pep-3119/)会为此工作吗? –

回答

6

我看过基于“isinstance()被认为有害的文章”,因为它打破了鸭子的打字。然而,至少我作为一个程序员想知道,如果不一定是一个对象从哪里获取函数,但是它是否实现了一个接口。

我认为你错过了这一点。

当我们谈论“鸭子打字”时,我们真正的意思是没有形式化我们的接口。因此,你试图做的事情归结为试图回答“我怎样才能使我的界面形式化,同时还没有形式化我的界面?”。

我们期待一个给我们实现一个接口的对象 - 我们描述的一个接口,不是通过创建一个基类,而是通过编写一堆文档和描述行为(如果我们感觉特别活泼,设置某种测试套件) - 因为我们说这是我们期望的(再次在我们的文档中)。我们通过尝试像使用它一样来验证对象是否实现了接口,并将任何由此产生的错误视为调用方的责任。调用给我们错误对象的代码是调皮的,这就是错误需要修复的地方。 (同样,测试帮助我们跟踪这些事情了。)

总之,测试isinstance(this_fuzzball_that_was_handed_to_me, Duck)并没有真正帮助的事项:

  • 它可以通过isinstance检查,但实现的方式方法是违反了我们的预期(或者说,return NotImplemented)。这里只有真正的测试。

  • 它可以通过检查,但实际上完全无法实现一个或多个方法;毕竟,基地Duck不包含任何实现,并且Python没有理由在派生类中检查它们。

  • 也许更重要的是,它可能会失败,即使它是一个完全可用的鸭子模糊球。也许这是一个不相关的对象,其具有quackwalklook直接功能,手动附加到它作为属性(而不是它的类的属性,它们成为查找时变成方法)。

好吧,那么,“不要那样做”,你说。但现在你为每个人做更多的工作;如果客户不要总是选择加入,那么对于使用鸭子的代码进行检查是没有用的和危险的。与此同时,你获得了什么?

这与EAFP的原理有关:不要试图通过查看它是否是鸭子;如果它是一只鸭子,把它当作一只鸭子来处理,如果它不是,则应该处理血腥的混乱。


但是,如果你不关心鸭打字理念,绝对必须强制严谨一些外表上的东西,你可能会感兴趣的标准库abc模块中。

1

尽管我不想高估这个术语,但是:您的方法不是pythonic。做鸭子打字,或者不要做。

如果你想确保你的“接口”实现实现它的一切应该:测试它!

对于较小的项目,很容易记住您需要什么。你可以简单地尝试它。

我同意,对于大型项目,甚至团队合作,最好确保您的类型具有所需的一切。在这种情况下,你绝对应该使用单元测试来确保你的类型是完整的。即使没有鸭子打字,你也需要测试,所以你可能不需要任何额外的测试。

Guido van Rossum在this talk中提到了一些关于鸭子打字的有趣想法。这非常鼓舞人心,绝对值得一看。

相关问题