什么是鸭子打字?

发布于 2024-10-02 22:39:49 字数 104 浏览 0 评论 0原文

鸭子打字在软件开发中意味着什么?

What does duck typing mean in software development?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

情释 2024-10-09 22:39:49

它是在没有 强类型

这个想法是,您不需要指定类型来调用对象上的现有方法 - 如果在其上定义了方法,您就可以调用它。

这个名字来源于一句话“如果它看起来像鸭子并且嘎嘎叫起来像鸭子,那么它就是鸭子”。

维基百科有更多信息。

It is a term used in dynamic languages that do not have strong typing.

The idea is that you don't need to specify a type in order to invoke an existing method on an object - if a method is defined on it, you can invoke it.

The name comes from the phrase "If it looks like a duck and quacks like a duck, it's a duck".

Wikipedia has much more information.

鲸落 2024-10-09 22:39:49

鸭子打字
意味着操作没有正式指定其操作数必须满足的要求,而只是用给定的内容尝试

与其他人所说的不同,这不一定与动态语言或继承问题有关。

示例任务:在对象上调用一些方法Quack

如果不使用鸭子类型,执行此任务的函数f必须提前指定其参数必须支持某种方法Quack。一种常见的方法是使用接口

interface IQuack { 
    void Quack();
}

void f(IQuack x) { 
    x.Quack(); 
}

调用 f(42) 失败,但只要 donald 是一个实例,f(donald) 就可以工作IQuack 子类型。

另一种方法是结构类型 - 但同样,方法Quack()被正式指定为任何不能提前证明它是quack的东西都会导致编译器失败。

def f(x : { def Quack() : Unit }) = x.Quack() 

我们甚至可以用 Haskell 编写

f :: Quackable a => a -> IO ()
f = quack

,其中 Quackable 类型类确保我们方法的存在。


So how does **duck typing** change this?

嗯,正如我所说,鸭子类型系统没有指定要求,但只是尝试是否有效

因此,像 Python 这样的动态类型系统总是使用鸭子类型:

def f(x):
    x.Quack()

如果 f 得到一个支持 Quack()x,那么一切都很好,如果不,它会在运行时崩溃。

但鸭子类型根本不意味着动态类型 - 事实上,有一种非常流行但完全静态的鸭子类型方法,它也没有给出任何要求:

template <typename T>
void f(T x) { x.Quack(); } 

该函数不会以任何方式表明它需要一些 x 可以Quack,所以它只是在编译时尝试,如果一切正常,那就没问题了。

Duck typing
means that an operation does not formally specify the requirements that its operands have to meet, but just tries it out with what is given.

Unlike what others have said, this does not necessarily relate to dynamic languages or inheritance issues.

Example task: Call some method Quack on an object.

Without using duck-typing, a function f doing this task has to specify in advance that its argument has to support some method Quack. A common way is the use of interfaces

interface IQuack { 
    void Quack();
}

void f(IQuack x) { 
    x.Quack(); 
}

Calling f(42) fails, but f(donald) works as long as donald is an instance of a IQuack-subtype.

Another approach is structural typing - but again, the method Quack() is formally specified anything that cannot prove it quacks in advance will cause a compiler failure.

def f(x : { def Quack() : Unit }) = x.Quack() 

We could even write

f :: Quackable a => a -> IO ()
f = quack

in Haskell, where the Quackable typeclass ensures the existence of our method.


So how does **duck typing** change this?

Well, as I said, a duck typing system does not specify requirements but just tries if anything works.

Thus, a dynamic type system as Python's always uses duck typing:

def f(x):
    x.Quack()

If f gets an x supporting a Quack(), everything is fine, if not, it will crash at runtime.

But duck typing doesn't imply dynamic typing at all - in fact, there is a very popular but completely static duck typing approach that doesn't give any requirements too:

template <typename T>
void f(T x) { x.Quack(); } 

The function doesn't tell in any way that it wants some x that can Quack, so instead it just tries at compile time and if everything works, it's fine.

回眸一笑 2024-10-09 22:39:49

简单解释

什么是鸭子类型?

“如果它像鸭子一样行走,像......等一样嘎嘎叫” - 是的,但这是什么意思??!

我们对“物体”感兴趣能做什么,而不是他们是什么

让我们用一个例子来解压它:

Duck Typing 的解释

有关更多详细信息,请参阅下文:

Duck Typing 功能示例:

想象我有一根魔杖。它具有特殊的权力。如果我挥动魔杖并对一辆车说“开车!”,那么它就会开车了!

对其他事情也有效吗?不确定:所以我在卡车上尝试一下。哇——它也能开车!然后我在飞机、火车和 1 Woods 上尝试(它们是一种人们用来“击球”高尔夫球的高尔夫球杆)。 他们都开车!

但是它能用在茶杯上吗?错误:KAAAA-BOOOOOOM!结果不太好。 ====>茶杯不能开车!!呃!?

这基本上就是鸭子类型的概念。这是一个先试后买系统。如果有效的话,一切都好。但如果失败了,就像手榴弹还在你手里一样,它就会在你脸上爆炸。

换句话说,我们感兴趣的是对象可以做什么,而不是对象是什么

C# 或 Java 等语言怎么样?

如果我们关心对象实际上是什么,那么我们的魔术将只对预设的、授权的类型起作用 - 在本例中是汽车,但对其他可以驾驶的对象将失败:卡车、轻便摩托车、嘟嘟车等。它不适用于卡车,因为我们的魔杖预计它仅适用于汽车

换句话说,在这种情况下,魔杖非常仔细地观察对象是什么(它是汽车吗?),而不是对象可以做什么(例如是否汽车、卡车等都可以驾驶)。

让卡车开起来的唯一方法是,如果你能以某种方式让魔杖同时期待卡车和汽车(也许通过“实现通用接口”)。这可以通过一种称为“多态性”的技术或使用“接口”来完成 - 它们有点相同。如果您喜欢卡通并需要解释,请查看我的界面卡通

摘要:关键要点

在鸭子类型中,重要的是对象实际上可以做什么,而不是对象是什么

代码示例

但是高尔夫球杆如何能像汽车一样“驾驶”呢?他们不一样吗?如果您使用像 Ruby 这样的语言,我们不关心对象是什么:

class Car
   def drive
      "I"m driving a Car!"
   end
end

class GolfClub
   def drive
      "I"m driving a golf club!"
   end 
end

def test_drive(item)   
   item.drive # don't care what it is, all i care is that it can "drive"
end

car = Car.new
test_drive(car) #=> "I'm driving a Car"

club = GolfClub.new
test_drive(club) #=> "I"m driving a GolfClub"

# welcome to duck typing!

PS。我想删掉学术上的废话:这个答案并不科学,但希望它能让你通过类比对正在发生的事情有一个模糊的理解。

聚苯硫醚。如果你想笑并且有空闲时间,请查看:Matt Damon 在善意狩猎中对鸭子打字的解释;)

Simple Explanation

What is duck typing?

“If it walks like a duck and quacks like a.... etc” - YES, but what does that mean??!

We're interested in what "objects" can do, rather than what they are.

Let's unpack it with an example:

Explanation of Duck Typing

See below for further detail:

Examples of Duck Typing functionality:

Imagine I have a magic wand. It has special powers. If I wave the wand and say "Drive!" to a car, well then, it drives!

Does it work on other things? Not sure: so I try it on a truck. Wow - it drives too! I then try it on planes, trains and 1 Woods (they are a type of golf club which people use to 'drive' a golf ball). They all drive!

But would it work on say, a teacup? Error: KAAAA-BOOOOOOM! that didn't work out so good. ====> Teacups can't drive!! duh!?

This is basically the concept of duck typing. It's a try-before-you-buy system. If it works, all is well. But if it fails, like a grenade still in your hand, it's gonna blow up in your face.

In other words, we are interested in what the object can do, rather than with what the object is.

What about languages like C# or Java etc?

If we were concerned with what the object actually was, then our magic trick will work only on pre-set, authorised types - in this case cars, but will fail on other objects which can drive: trucks, mopeds, tuk-tuks etc. It won't work on trucks because our magic wand is expecting it to only work on cars.

In other words, in this scenario, the magic wand looks very closely at what the object is (is it a car?) rather than what the object can do (e.g. whether cars, trucks etc. can drive).

The only way you can get a truck to drive is if you can somehow get the magic wand to expect both trucks and cars (perhaps by "implementing a common interface"). This can be done via a technique called: "polymorphism" or by using "interfaces" - they're kinda the same thing. If you like cartoons and want an explanation, check out my cartoon on interfaces.

Summary: Key take-out

What's important in duck typing is what the object can actually do, rather than what the object is.

Code Sample

But how can a golf club "drive" like a car? Aren't they different? If you're using a language like Ruby, we don't care about what the object is:

class Car
   def drive
      "I"m driving a Car!"
   end
end

class GolfClub
   def drive
      "I"m driving a golf club!"
   end 
end

def test_drive(item)   
   item.drive # don't care what it is, all i care is that it can "drive"
end

car = Car.new
test_drive(car) #=> "I'm driving a Car"

club = GolfClub.new
test_drive(club) #=> "I"m driving a GolfClub"

# welcome to duck typing!

PS. I wanted to cut out the academic rigmarole: this answer is not scientific, but hopefully it gives you a vague understanding of what is going on via analogy.

PPS. if you wanna laugh and got some time to spare, check out: Matt Damon's explanation of duck typing in Good Will Hunting ;)

羁客 2024-10-09 22:39:49

假设您正在设计一个简单的函数,该函数获取 Bird 类型的对象并调用其 walk() 方法。您可以想到两种方法:

  1. 这是我的函数,我必须确保它只接受 Bird 类型,否则代码将无法编译。如果有人想使用我的函数,他们必须知道我只接受Bird
  2. 我的函数获取任何对象,我只需调用该对象的walk() 方法。因此,如果对象可以walk()那么它是正确的。如果不能,我的功能就会失败。因此,这里对象是Bird还是其他东西并不重要,重要的是它可以walk()(这是鸭子打字)。

必须考虑到,鸭子打字在某些情况下可能很有用。例如,Python 经常使用鸭子类型。


有用的阅读

Consider you are designing a simple function which gets an object of type Bird and calls its walk() method. There are two approaches you can think of:

  1. This is my function, and I must be sure that it only accepts the Bird type or the code will not compile. If anyone wants to use my function, they must be aware that I only accept Birds.
  2. My function gets any objects and I just call the object's walk() method. So, if the object can walk() then it is correct. If it can't, my function will fail. So, here it is not important the object is a Bird or anything else, it is important that it can walk() (This is duck typing).

It must be considered that duck typing may be useful in some cases. For example, Python uses duck typing a lot.


Useful reading

萌酱 2024-10-09 22:39:49

我看到很多答案都重复了老套路:

如果它看起来像鸭子并且嘎嘎叫起来像鸭子,那么它就是鸭子

,然后深入解释如何使用鸭子类型,或者一个似乎进一步混淆概念的示例。

我没有找到那么多帮助。

这是我发现的关于鸭子类型的简单英语答案的最佳尝试:

鸭子类型意味着一个对象是由它可以做什么来定义的,而不是由

这意味着我们不太关心对象的类/类型,而更关心可以对其调用哪些方法以及可以对其执行哪些操作。 我们不关心它的类型,我们关心它能做什么

I see a lot of answers that repeat the old idiom:

If it looks like a duck and quacks like a duck, it's a duck

and then dive into an explanation of what you can do with duck typing, or an example which seems to obfuscate the concept further.

I don't find that much help.

This is the best attempt at a plain english answer about duck typing that I have found:

Duck Typing means that an object is defined by what it can do, not by
what it is.

This means that we are less concerned with the class/type of an object and more concerned with what methods can be called on it and what operations can be performed on it. We don't care about it's type, we care about what it can do.

厌倦 2024-10-09 22:39:49

别做庸医;我支持你:

“鸭子打字” := “尝试方法,不要检查类型”

注意::= 可以读作 “定义为”

鸭子类型”的意思是:只需在传入的任何对象上尝试方法(函数调用),而不是首先检查对象的类型看看该方法是否是对此类类型的有效调用。

我们将其称为“尝试方法,不要检查类型”输入,“方法调用”类型检查”,或者简称为“方法调用类型”

在下面的较长解释中,我将更详细地解释这一点,并帮助您理解“鸭子打字”这个荒谬、深奥且令人困惑的术语。


更长的解释:

Don't be a quack; I've got your back:

"Duck typing" := "try the methods, don't check the type"

Note: := can be read as "is defined as".

"Duck typing" means: just try the method (function call) on whatever object comes in rather than checking the object's type first to see if that method is even a valid call on such a type.

Let's call this "try the methods, don't check the type" typing, "method-call type-checking", or just "method-call typing" for short.

In the longer explanation below, I'll explain this more in detail and help you make sense of the ridiculous, esoteric, and obfuscated term "duck typing."


Longer explanation:

DIE ???? DIE! ????

Python does this concept above. Consider this example function:

def func(a):
    a.method1()
    a.method2()

When the object (input parameter a) comes into the function func(), the function shall try (at run time) to call any methods specified on this object (namely: method1() and method2() in the example above), rather than first checking to see if a is some "valid type" which has these methods.

So, it's an action-based attempt at run-time, NOT a type-based check at compile-time or run-time.

Now look at this silly example:

def func(duck_or_duck_like_object):
    duck_or_duck_like_object.quack()
    duck_or_duck_like_object.walk()
    duck_or_duck_like_object.fly()
    duck_or_duck_like_object.swim()

Hence is born the ridiculous phrase:

If it walks like a duck and quacks like a duck then it is a duck.

The program that uses "duck typing" shall simply try whatever methods are called on the object (in this example above: quack(), walk(), fly(), and swim()) withOUT even knowing the type of the object! It just tries the methods! If they work, great, for all the "duck typing" language knows or cares, IT (the object passed in to the function) IS A DUCK!--because all the (duck-like) methods worked on it.

(Summarizing my own words):

A "duck typed" language shall not check its type (neither at compile time nor run-time)--it doesn't care to. It will just try the methods at run-time. If they work, great. If they don't, then it shall throw a run-time error.

That is duck-typing.

I'm so tired of this ridiculous "duck" explanation (because without this full explanation it doesn't make any sense at all!), and so are others too it sounds like. Example: from BKSpurgeon's answer here (my emphasis in bold):

(“If it walks like a duck and quacks like a duck then it is a duck.”) - YES! but what does that mean??!"

Now I get it: just try the method on whatever object comes in rather than checking the object's type first.

I shall call this "run-time checking where the program just tries the methods called without even knowing if the object has these methods, rather than checking the type of the object first as the means of knowing the object has these methods", because that just makes more sense. But...that's too long to say, so people would rather confuse each other for years instead by saying ridiculous but catchy things like "duck typing."

Let's instead call this: "try the methods, don't check the type" typing. Or, perhaps: "method-call type-checking" ("method-call typing" for short), or "indirect type-checking by method calls", since it uses the calling of a given method as "proof enough" that the object is of the right type, rather than checking the object's type directly.

Note that this "method-call type-checking" (otherwise confusingly called "duck typing") is a type of dynamic typing. But, NOT all dynamic typing is necessarily "method call type-checking", because dynamic typing, or type checking at run-time, can also be done by actually checking an object's type rather than by simply attempting to call the methods called on the object in the function without knowing its type.

Read also:

  1. https://en.wikipedia.org/wiki/Duck_typing --> search the page for "run", "run time", and "runtime".
何其悲哀 2024-10-09 22:39:49

维基百科有一个相当详细的解释:

http://en.wikipedia.org/wiki/Duck_typing

鸭子打字是一种动态风格
输入当前对象的位置
方法和属性集
确定有效的语义,而不是
比它从特定的继承
特定的类或实现
界面。

重要的一点是,对于鸭子类型,开发人员可能更关心所使用的对象的部分,而不是实际的底层类型。

Wikipedia has a fairly detailed explanation:

http://en.wikipedia.org/wiki/Duck_typing

duck typing is a style of dynamic
typing in which an object's current
set of methods and properties
determines the valid semantics, rather
than its inheritance from a particular
class or implementation of a specific
interface.

The important note is likely that with duck typing a developer is concerned more with the parts of the object that are consumed rather than what the actual underlying type is.

冷默言语 2024-10-09 22:39:49

马特·达蒙在《善意狩猎

记录》中解释了鸭子打字如下。 视频链接位于此处。

CHUCKIE:好吧,我们会有问题吗?

克拉克:没问题。我只是希望你能给我一些关于鸭子打字实际上是什么的见解?我的观点是鸭子绑定没有明确定义,强

WILL: [interrupting] 也没有明确定义……强类型也没有明确定义。当然这是你的论点。你是一年级研究生:你刚刚读完一些关于鸭子打字的文章,可能是在 Rails 论坛上,你会确信这一点,直到下个月你到达四人帮,然后你我们将讨论 Google Go 和 Ocaml 如何成为具有结构子绑定结构的统计类型语言。这种情况会持续到明年,直到您可能会在这里反复回忆 Matz,谈论 Ruby 3.0 之前的乌托邦以及 GC 上子类型的内存分配效果。

CLARK:[大吃一惊]事实上我不会,因为 Matz 大大低估了 -

WILL 的影响:“Matz 大大低估了 Ruby 3.0 的 GC 对性能的影响。你是从 Donald Knuth 那里得到的,《计算机编程的艺术》,第 98 页,对吗?是的,我也读过这句话,你是否打算为我们抄袭整个内容——你自己对此事有什么想法吗?你的东西,你进入堆栈溢出,你读了一些关于 r/ruby 的晦涩难懂的文章,然后你假装,你把它当作你自己的——你自己的想法只是为了给一些女孩留下深刻的印象,让我的朋友难堪

意志:看到像你这样的人的悲伤之处在于,大约 50 年后,你将开始自己进行一些思考,然后你会发现以下事实:存在三个确定性第一,不要这样做。第二,如果它像鸭子一样行走,那么它就是鸭子。第三,你在通过堆栈溢出答案可以得到的教育上投入了一百五十美元。本·科希。

CLARK:是的,但我会获得学位,并且在我们去滑雪旅行的路上,您将通过在得来速餐厅的 React 为我的孩子们提供一些便宜的 html。

WILL:[微笑]是的,也许吧。但至少我不会没有原创性。

(稍顿)

WILL:你有问题3吗?我想我们可以出去解决问题。

克拉克:没问题

一段时间后:

威尔:你喜欢苹果吗?

克拉克就像,是吧?

威尔:你喜欢这些苹果吗? (砰:威尔将一封信猛地撞在窗户上。)我必须接受谷歌的报价! (向克拉克展示了录取通知书,其中显示了他的面试答案:一张鸭子行走、说话、行为像鹅的照片。)

滚动积分

结束。

(这是旧答案的脚注:)

3代码问题的出现。

Matt Damon explains Duck Typing in Good Will Hunting

Transcript is as below. Video link here..

CHUCKIE: All right, are we gonna have a problem?

CLARK: There's no problem. I was just hoping you could give me some insight into what duck typing is actually is? My contention is that duck tying is not well defined, and neither is strong

WILL: [interrupting] …and neither is strong typing. Of course that's your contention. You're a first year grad student: you just got finished reading some article on duck typing, probably on a rails forum, and you’re gonna be convinced of that until next month when you get to the Gang of Four, and then you’re gonna be talking about how Google Go and Ocaml are statistically typed languages with structural sub-tying construction. That's going to last until next year, till you're probably gonna be in here regurgitating Matz, talkin’ about, you know, the Pre-Ruby 3.0 utopia and the memory allocating effects of sub-typing on the GC.

CLARK: [taken aback] Well as a matter of fact I won't, because Matz drastically underestimates the impact of —

WILL: "Matz dramatically underestimates the impact of Ruby 3.0's GC on performance. You got that from Donald Knuth, The Art of Computer Programming, page 98, right? Yeah I read that too. Were you gonna plagiarize the whole thing for us—you have any thoughts of—of your own on this matter? Or do—is that your thing, you come into stack overflow, you read some obscure passage on r/ruby and then you pretend, you pawn it off as your own—your own idea just to impress some girls, embarrass my friend?

[Clark is stunned]

WILL: See the sad thing about a guy like you is in about 50 years you’re gonna start doing some thinking on your own and you’re gonna come up with the fact that there are three certainties in life. One, don't do that. And two, if it walks like a duck then it is a duck. And three, you dropped a hundred and fifty grand on an education you coulda got for zero cents via a stack overflow answer by Ben Koshy.

CLARK: Yeah, but I will have a degree, and you'll be serving my kids some cheap html via react at a drive-thru on our way to a skiing trip.

WILL: [smiles] Yeah, maybe. But at least I won't be unoriginal.

(a beat)

WILL: you got problem 3 ? I guess we can step outside and sort things out.

Clark: there's no problem

Some time later:

WILL: Do you like apples?

Clark is like, huh?

WILL: How do you like them apples? (Boom: Will slams a letter up against a window.) I gotta offer from Google! (Shows the letter of acceptance to Clark showing his interview answer: a picture of a duck walking, and talking, and acting like a... goose.)

Roll Credits.

THE END.

(This is a footnote to the old answer here:)

3 Advent of Code problems.

森罗 2024-10-09 22:39:49

我知道我没有给出笼统的答案。在 Ruby 中,我们不声明变量或方法的类型——一切都只是某种对象。
所以规则是“类不是类型”

在 Ruby 中,类永远不是(好吧,几乎永远不是)类型。相反,对象的类型更多地由该对象可以执行的操作来定义。在 Ruby 中,我们称之为鸭子类型。如果一个物体像鸭子一样走路并且像鸭子一样说话,那么解释器很乐意将其视为鸭子。

例如,您可能正在编写一个例程来将歌曲信息添加到字符串中。如果您有 C# 或 Java 背景,您可能会想这样写:

def append_song(result, song)
    # test we're given the right parameters 
    unless result.kind_of?(String)
        fail TypeError.new("String expected") end
    unless song.kind_of?(Song)
        fail TypeError.new("Song expected")
end

result << song.title << " (" << song.artist << ")" end
result = ""

append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

拥抱 Ruby 的鸭子类型,您会写出更简单的东西:

def append_song(result, song)
    result << song.title << " (" << song.artist << ")"
end

result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

您不需要检查参数的类型。如果他们支持<< (就结果而言)或标题和艺术家(就歌曲而言),一切都会正常进行。如果不这样做,您的方法无论如何都会抛出异常(就像检查类型时会发生的情况一样)。但如果没有检查,你的方法突然变得更加灵活。您可以向它传递一个数组、一个字符串、一个文件或使用 << 附加的任何其他对象,它就会正常工作。

I know I am not giving generalized answer. In Ruby, we don’t declare the types of variables or methods— everything is just some kind of object.
So Rule is "Classes Aren’t Types"

In Ruby, the class is never (OK, almost never) the type. Instead, the type of an object is defined more by what that object can do. In Ruby, we call this duck typing. If an object walks like a duck and talks like a duck, then the interpreter is happy to treat it as if it were a duck.

For example, you may be writing a routine to add song information to a string. If you come from a C# or Java background, you may be tempted to write this:

def append_song(result, song)
    # test we're given the right parameters 
    unless result.kind_of?(String)
        fail TypeError.new("String expected") end
    unless song.kind_of?(Song)
        fail TypeError.new("Song expected")
end

result << song.title << " (" << song.artist << ")" end
result = ""

append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

Embrace Ruby’s duck typing, and you’d write something far simpler:

def append_song(result, song)
    result << song.title << " (" << song.artist << ")"
end

result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

You don’t need to check the type of the arguments. If they support << (in the case of result) or title and artist (in the case of song), everything will just work. If they don’t, your method will throw an exception anyway (just as it would have done if you’d checked the types). But without the check, your method is suddenly a lot more flexible. You could pass it an array, a string, a file, or any other object that appends using <<, and it would just work.

鹤仙姿 2024-10-09 22:39:49

看看语言本身可能会有所帮助;它经常对我有帮助(我的母语不是英语)。

鸭子打字中:

1)打字这个词并不意味着在键盘上打字(就像我脑海中持久的图像一样),它意味着确定“什么类型一个东西的就是那个东西?

2)duck这个词表达了如何确定;这是一种“松散”的确定,例如:“如果它像鸭子一样行走......那么它就是鸭子”。它是“松散的”,因为这个东西可能是鸭子,也可能不是,但它是否真的是鸭子并不重要;它是鸭子。重要的是我可以用它做我能用鸭子做的事情,并期望鸭子表现出的行为。我可以给它喂面包屑,它可能会朝我冲过来,或者冲向我,或者后退……但它不会像灰熊那样吞噬我。

Looking at the language itself may help; it often helps me (I'm not a native English speaker).

In duck typing:

1) the word typing does not mean typing on a keyboard (as was the persistent image in my mind), it means determining "what type of a thing is that thing?"

2) the word duck expresses how is that determining done; it's kind of a 'loose' determining, as in: "if it walks like a duck ... then it's a duck". It's 'loose' because the thing may be a duck or may not, but whether it actually is a duck doesn't matter; what matters is that I can do with it what I can do with ducks and expect behaviors exhibited by ducks. I can feed it bread crumbs and the thing may go towards me or charge at me or back off ... but it will not devour me like a grizzly would.

抽个烟儿 2024-10-09 22:39:49

鸭子打字:

如果它像鸭子一样说话和走路,那么它就是鸭子

这通常称为溯因溯因推理,也称为逆向,一种更清晰的推理我认为的定义):

  • 来自C(结论,我们所看到的)和R(规则,我们所知道的< /em>),我们接受/决定/假设P(前提,属性)换句话说是给定的事实

    ...医学诊断的基础

    与鸭子:C = 走路、说话R = 像鸭子P = 这是一只鸭子

回到编程:

  • 对象o有方法/属性mp1和接口/输入T
    需要/定义mp1

  • 对象 o 具有方法/属性 mp2 和接口/类型 T 需要/定义mp2

  • ...

因此,不仅仅是在任何对象上接受 mp1...,只要它满足 的某些定义mp1...,编译器/运行时也应该可以接受断言 o 的类型为 T

那么,上面的示例是否属于这种情况? Duck 打字本质上根本就不是打字吗?或者我们应该称之为隐式类型?

Duck typing:

If it talks and walks like a duck, then it is a duck

This is typically called abduction (abductive reasoning or also called retroduction, a clearer definition I think):

  • from C (conclusion, what we see) and R (rule, what we know), we accept/decide/assume P (Premise, property) in other words a given fact

    ... the very basis of medical diagnosis

    with ducks: C = walks, talks, R = like a duck, P = it's a duck

Back to programming:

  • object o has method/property mp1 and interface/type T
    requires/defines mp1

  • object o has method/property mp2 and interface/type T requires/defines mp2

  • ...

So, more than simply accepting mp1... on any object as long has it meets some definition of mp1..., compiler/runtime should also be okay with the assertion o is of type T

And well, is it the case with examples above? Is Duck typing is essentially no typing at all? Or should we call it implicit typing?

顾冷 2024-10-09 22:39:49

鸭子打字不是类型提示!

基本上,为了使用“鸭子类型”,您不会通过使用通用接口来针对特定类型,而是针对更广泛的子类型(不是谈论继承,当我指的是子类型时,我指的是适合相同配置文件的“事物”) 。

您可以想象一个存储信息的系统。为了写入/读取信息,您需要某种存储和信息。

存储类型可能是:文件、数据库、会话等。

无论存储类型如何,该界面都会让您知道可用的选项(方法),这意味着此时还没有实现任何内容!换句话说,接口对如何存储信息一无所知。

每个存储系统都必须通过实现完全相同的方法来知道该接口的存在。

interface StorageInterface
{
   public function write(string $key, array $value): bool;
   public function read(string $key): array;
}


class File implements StorageInterface
{
    public function read(string $key): array {
        //reading from a file
    }

    public function write(string $key, array $value): bool {
         //writing in a file implementation
    }
}


class Session implements StorageInterface
{
    public function read(string $key): array {
        //reading from a session
    }

    public function write(string $key, array $value): bool {
         //writing in a session implementation
    }
}


class Storage implements StorageInterface
{
    private $_storage = null;

    function __construct(StorageInterface $storage) {
        $this->_storage = $storage;
    }

    public function read(string $key): array {
        return $this->_storage->read($key);
    }

    public function write(string $key, array $value): bool {
        return ($this->_storage->write($key, $value)) ? true : false;
    }
}

所以现在,每次您需要写入/读取信息时:

$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');

$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');

在此示例中,您最终会在存储构造函数中使用 Duck Typing:

function __construct(StorageInterface $storage) ...

希望它有所帮助;)

Duck Typing is not Type Hinting!

Basically in order to use "duck typing" you will not target a specific type but rather a wider range of subtypes (not talking about inheritance, when I mean subtypes I mean "things" that fit within the same profiles) by using a common interface.

You can imagine a system that stores information. In order to write/read information you need some sort of storage and information.

Types of storage may be: file, database, session etc.

The interface will let you know the available options (methods) regardless of the storage type, meaning that at this point nothing is implemented! In another words the Interface doesn't know nothing about how to store information.

Every storage system must know the existence of the interface by implementing it's very same methods.

interface StorageInterface
{
   public function write(string $key, array $value): bool;
   public function read(string $key): array;
}


class File implements StorageInterface
{
    public function read(string $key): array {
        //reading from a file
    }

    public function write(string $key, array $value): bool {
         //writing in a file implementation
    }
}


class Session implements StorageInterface
{
    public function read(string $key): array {
        //reading from a session
    }

    public function write(string $key, array $value): bool {
         //writing in a session implementation
    }
}


class Storage implements StorageInterface
{
    private $_storage = null;

    function __construct(StorageInterface $storage) {
        $this->_storage = $storage;
    }

    public function read(string $key): array {
        return $this->_storage->read($key);
    }

    public function write(string $key, array $value): bool {
        return ($this->_storage->write($key, $value)) ? true : false;
    }
}

So now, every time you need to write/read information:

$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');

$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');

In this example you end up using Duck Typing in Storage constructor:

function __construct(StorageInterface $storage) ...

Hope it helped ;)

百变从容 2024-10-09 22:39:49

使用鸭子打字技术进行树遍历

def traverse(t):
    try:
        t.label()
    except AttributeError:
        print(t, end=" ")
    else:
        # Now we know that t.node is defined
        print('(', t.label(), end=" ")
        for child in t:
            traverse(child)
        print(')', end=" ")

Tree Traversal with duck typing technique

def traverse(t):
    try:
        t.label()
    except AttributeError:
        print(t, end=" ")
    else:
        # Now we know that t.node is defined
        print('(', t.label(), end=" ")
        for child in t:
            traverse(child)
        print(')', end=" ")
陈甜 2024-10-09 22:39:49

在编程中,类型可以分为名义类型和结构类型。名义类型考虑类型的整个结构。那么从谁那里继承的等等。它们显然比结构类型更复杂。例如,在 C# 和 Java 中,一种使用名义类型。

结构类型根本不考虑这些点。对于结构类型,只有单一类型的结构很重要。那么它看起来怎么样。以一个类为例。它是否具有相同的参数和预期的类型。这称为鸭子打字。鸭子打字起源于鸭子测试。

Dugtest 的意思是:如果某物看起来像鸭子。如果它像鸭子一样游泳。如果它像鸭子一样嘎嘎叫。那么它就是一只鸭子。相反:如果测试用例不适用,那么它就不是鸭子。 (https://en.wikipedia.org/wiki/Duck_test)

In programming, types can be divided into nominal and structural types. Nominal types consider the entire structure of a type. So from whom inherited etc. They are clearly more complex than structural types. One uses nominal types for example in C# and Java.

Structural types do not consider these points at all. For structural types only the structure of the single type is important. So how it looks like. In the example of a class. Does it have the same parameters and the expected types. This is called Duck Typing. Duck Typing finds its origin in the Duck Test.

A Dugtest means: If something looks like a duck. If it swims like a duck. If it quacks like a duck. Then it is a duck. Conversely: If a test case does not apply, then it is not a duck. (https://en.wikipedia.org/wiki/Duck_test)

最单纯的乌龟 2024-10-09 22:39:49

我认为混合动态类型、静态类型和鸭子类型是很混乱的。鸭子类型是一个独立的概念,甚至像 Go 这样的静态类型语言也可以有一个实现鸭子类型的类型检查系统。如果类型系统将检查(声明的)对象的方法而不是类型,那么它可以称为鸭子类型语言。

I think it's confused to mix up dynamic typing, static typing and duck typing. Duck typing is an independent concept and even static typed language like Go, could have a type checking system which implements duck typing. If a type system will check the methods of a (declared) object but not the type, it could be called a duck typing language.

月亮是我掰弯的 2024-10-09 22:39:49

鸭子打字这个术语是一个谎言<​​/strong>。

你会看到这句成语“如果它走起来像鸭子,嘎嘎叫起来像鸭子,那么它就是鸭子。”这句话在这里一次又一次地重复。

但这不是鸭子类型(或者我们通常所说的鸭子类型)我们所讨论的鸭子打字就是试图对某物施加命令,无论它是什么,但并不能推断该物体是否是一个物体。 对于真正

的鸭子类型,请参阅类型类
现在遵循这样的成语:“如果它像鸭子一样行走,像鸭子一样嘎嘎叫,那么它就是鸭子。”对于类型类,如果一个类型实现了类型类定义的所有方法,那么它可以被视为成员因此,如果有一个类型类 Duck 定义了某些方法(quack 和 walk-like-duck),则任何实现这些相同方法的都可以被视为 Duck(无需继承该类型类)。需要继承Duck)。

The term Duck Typing is a lie.

You see the idiom “If it walks like a duck and quacks like a duck then it is a duck." that is being repeated here time after time.

But that is not what duck typing (or what we commonly refer to as duck typing) is about. All that the Duck Typing we are discussing is about, is trying to force a command on something. Seeing whether something quacks or not, regardless of what it says it is. But there is no deduction about whether the object then is a Duck or not.

For true duck typing, see type classes.
Now that follows the idiom “If it walks like a duck and quacks like a duck then it is a duck.". With type classes, if a type implements all the methods that are defined by a type class, it can be considered a member of that type class (without having to inherit the type class). So, if there is a type class Duck which defines certain methods (quack and walk-like-duck), anything that implements those same methods can be considered a Duck (without needing to inherit Duck).

冷︶言冷语的世界 2024-10-09 22:39:49

在鸭子类型中,对象的适用性(例如,在函数中使用)是根据是否实现了某些方法和/或属性来确定的,而不是根据该对象的类型来确定的。

例如,在 Python 中,len 函数可以与实现 __len__ 方法的任何对象一起使用。它不关心该对象是否属于某种类型,例如字符串、列表、字典或 MyAwesomeClass,只要这些对象实现了 __len__ 方法,len 将与他们。

class MyAwesomeClass:
    def __init__(self, str):
        self.str = str
    
    def __len__(self):
        return len(self.str)

class MyNotSoAwesomeClass:
    def __init__(self, str):
        self.str = str

a = MyAwesomeClass("hey")
print(len(a))  # Prints 3

b = MyNotSoAwesomeClass("hey")
print(len(b))  # Raises a type error, object of type "MyNotSoAwesomeClass" has no len()

换句话说,MyAwesomeClass 看起来像鸭子,并且嘎嘎叫,因此是鸭子,而 MyNotSoAwesomeClass 看起来不像鸭子,也不会嘎嘎叫,因此不是鸭子!

In duck typing, an object's suitability (to be used in a function, for example) is determined based on whether certain methods and/or properties are implemented rather than based on the type of that object.

For example, in Python, the len function can be used with any object implementing the __len__ method. It doesn't care if that object is of a certain type say string, list, dictionary or MyAwesomeClass, as far as these objects implement a __len__ method, len will work with them.

class MyAwesomeClass:
    def __init__(self, str):
        self.str = str
    
    def __len__(self):
        return len(self.str)

class MyNotSoAwesomeClass:
    def __init__(self, str):
        self.str = str

a = MyAwesomeClass("hey")
print(len(a))  # Prints 3

b = MyNotSoAwesomeClass("hey")
print(len(b))  # Raises a type error, object of type "MyNotSoAwesomeClass" has no len()

In other words, MyAwesomeClass looks like a duck and quacks like a duck and therefore is a duck, while MyNotSoAwesomeClass doesn't look like a duck and doesn't quack, therefore is not a duck!

孤蝉 2024-10-09 22:39:49

鸭子类型:

let anAnimal 

if (some condition) 
  anAnimal = getHorse()
else
  anAnimal = getDog()

anAnimal.walk()

上面的函数调用在结构类型中不起作用

以下将适用于结构类型:

IAnimal anAnimal

if (some condition) 
      anAnimal = getHorse()
    else
      anAnimal = getDog()
    
anAnimal.walk()

仅此而已,我们中的许多人已经知道鸭子类型是直观的。

Duck Typing:

let anAnimal 

if (some condition) 
  anAnimal = getHorse()
else
  anAnimal = getDog()

anAnimal.walk()

The above function call will not work in Structural typing

The following will work for Structural typing:

IAnimal anAnimal

if (some condition) 
      anAnimal = getHorse()
    else
      anAnimal = getDog()
    
anAnimal.walk()

That's all, many of us already know duck typing is intuitively.

中性美 2024-10-09 22:39:49

我尝试以我的方式理解这句名言:
“Python 并不关心对象是否是真正的鸭子。
它所关心的是对象是否,首先是“嘎嘎”,其次是“像鸭子”。”

有一个很好的网站。 http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

作者指出,鸭子类型可以让你创建自己的类,这些类具有
它们自己的内部数据结构 - 但可以使用正常的 Python 语法进行访问。

I try to understand the famous sentence in my way:
"Python dose not care an object is a real duck or not.
All it cares is whether the object, first 'quack', second 'like a duck'."

There is a good website. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

The author pointed that duck typing let you create your own classes that have
their own internal data structure - but are accessed using normal Python syntax.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文