我刚刚阅读了关于 duck typing 的 Wikipedia 文章,我觉得我错过了关于我在 Java 中使用的接口(interface)概念的重要一点:
"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck."
class Duck:
def quack(self):
print("Quaaaaaack!")
def feathers(self):
print("The duck has white and gray feathers.")
def swim(self):
print("Swim seamlessly in the water")
class Person:
def quack(self):
print("The person imitates a duck.")
def feathers(self):
print("The person takes a feather from the ground and shows it.")
def name(self):
print("John Smith")
def in_the_forest(duck):
duck.quack()
duck.feathers()
def game():
donald = Duck()
john = Person()
in_the_forest(donald)
in_the_forest(john)
game()
如果我在 in_the_forest
中写道:
- 它
quack
像鸭子吗?是的 - 它有鸭子
feathers
吗?是的 - 太好了,我们有一只鸭子!
后来,因为我知道它是一只鸭子,我想让它游泳
? john
会下沉!
我不希望我的应用程序在其进程中间崩溃(随机)因为 John 假装是一只鸭子,但我想检查对象的每个属性不是一个明智的主意我收到了...?
最佳答案
Duck 打字并不是要检查你需要的东西是否在那里然后使用它们。鸭子打字就是使用你需要的东西。
in_the_forest
函数是由一个正在考虑鸭子的开发人员编写的。它被设计为在 Duck
上运行.一个 Duck
可以quack
和 feathers
,因此编码人员使用这些功能来完成手头的工作。在这种情况下,Duck
也可以swim
没用过,也不需要。
在像 Java 这样的静态语言中,in_the_forest
会被宣布采取Duck
.当编码员后来发现他们有一个 Person
(也可以 quack
和 feathers
)并且想要重用该功能,但他们不走运。是 Person
Duck
的子类?不,这似乎一点也不合适。有没有QuacksAndFeathers
界面?也许,如果我们幸运的话。否则我们只好做一个,去修改Duck
实现它,并修改in_the_forest
拍QuacksAndFeathers
而不是 Duck
.如果 Duck
,这可能是不可能的。位于外部库中。
在 Python 中,您只需将 Person 传递给 in_the_forest
它有效。因为事实证明in_the_forest
不需要Duck
,它只需要一个“鸭子样”的对象,在这种情况下 Person 就足够鸭子样了。
game
但是,需要一个不同的“鸭式”定义,它稍微强一些。在这里,John Smith 倒霉了。
现在,Java 确实会在编译时捕捉到这个错误,而 Python 不会。这可以被视为一个劣势。支持动态类型的反对论点是说,您编写的任何实质性代码体都将始终包含 no 编译器可以捕获的错误(老实说,Java 甚至不是一个特别好的示例具有强大的静态检查以捕获大量错误的编译器)。所以你需要测试你的代码来找到那些错误。如果您正在测试这些错误,您会很容易找到通过 Person
的错误。到需要 Duck
的函数.鉴于此,动态打字员说,一种因为发现一些你的小错误而诱使你不测试的语言实际上是一种坏事物。最重要的是,它会阻止你做一些真正有用的事情,比如重用 in_the_forest
Person
上的函数.
就我个人而言,我被两个方向撕裂了。我真的很喜欢 Python 的灵事件态类型。我真的很喜欢 Haskell 和 Mercury因为他们强大的静态类型系统。我不太喜欢 Java 或 C++。在我看来,他们拥有静态类型的所有坏处,而好的部分却很少。
关于python - 鸭子打字和(java)接口(interface)概念,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6579671/