ダックタイピングとは何ですか?


429

ソフトウェアのランダムなトピックをオンラインで読んでいるときに、ダックタイピングという用語に出くわしましたが、完全に理解していませんでした。

「ダックタイピング」とは何ですか?


1
@ミッチ私はいくつかの形の継承として何かを試してみました。しかし、あまり従うことができませんでした。間違った質問をした場合は申し訳ありません。
sushil bharwani 2010年

3
@sushil bharwani:いいえ、怒りません。しかし、人々は最初の呼び出しのポート(つまり、最初に行うこと)として、ここに投稿する前に検索を試みることを期待しています。
ミッチウィート

104
上記の議論を考えると、スタックオーバーフローが実際に必要であるとは思えないのは、考えられるほぼすべての質問がインターネット上のどこかで答えられると私は確信しているからです。知識豊富な友達。多くの人がスタックオーバーフローのポイントを逃したと思います。
rhody 2014

41
私は、SOが「標準的な質問のリポジトリ」になることを意図してどこかで読んだと思いますが、これよりも多くの標準的なものを入手することはできません。
heltonbiker 14年

回答:


302

これは、強い型付けを持たない動的言語で使用される用語です。

アイデアは、オブジェクトの既存のメソッドを呼び出すために型を必要としないということです。メソッドが定義されている場合は、それを呼び出すことができます。

名前は、「アヒルのように見え、アヒルのように鳴く場合、それはアヒルです」というフレーズに由来します。

ウィキペディアにはもっと多くの情報があります。


25
厳密な型指定を使用することに注意してください。それはそれほど明確に定義されていません。ダックタイピングも同様です。Google GoまたはOcamlは、静的に型付けされた言語であり、構造サブタイピング-構造を備えています。これらのアヒル型言語ですか?
私は

7
アヒルのタイピングに適したフレーズは、「もしアヒルだと言うなら、私には十分です」です。pyvideo.org/video/1669/keynote-3 28:30またはyoutube.com/watch?v=NfngrdLv9ZQ#t=1716
tovmeod

7
ダックタイピングは、必ずしも動的言語で使用されるだけではありません。Objective-Cは動的言語ではなく、ダックタイピングを使用します。
eyuelt 2013年

12
PythonとRubyはどちらも厳密に型指定された言語であり、どちらもDuck Typingを備えています。文字列タイピングは、ダックタイピングがないことを意味するものではありません。
alanjds 14

8
私はこれに反対票を投じています。アヒルのダッキングは、型の強さとは関係ありません。インターフェイスを持つかどうかに関係なく、メソッドを持つ任意のオブジェクトを使用できるようにするだけです。
e-satis、2015年

209

ダックタイピング とは、演算がそのオペランドが満たす必要のある要件を正式に指定するのではなく、与えられたものを使って試すことを意味します。

他の人が言ったこととは異なり、これは必ずしも動的言語や継承の問題に関連しているわけではありません。

タスクの例:Quackオブジェクトのメソッドを呼び出す。

ダックタイピングを使用しない場合、fこのタスクを実行する関数は、引数が何らかのメソッドをサポートする必要があることを事前に指定する必要がありますQuack。一般的な方法は、インターフェースの使用です

interface IQuack { 
    void Quack();
}

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

呼び出しはf(42)失敗しますが、f(donald)限りとして働くdonaldのインスタンスであるIQuack-subtype。

もう1つのアプローチは構造型付けです。ただし、このメソッドQuack()も正式に指定されているためquack、事前にそれが原因でコンパイラエラーが発生することを証明できません。

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

私たちは書くことさえできました

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

Quackableクラスがメソッドの存在を保証するHaskellで。


では、アヒルのタイピングはどのようにこれを変えるのでしょうか?

まあ、私が言ったように、アヒルのタイピングシステムは要件を指定せず、何かが機能するかどうかを試すだけです。

したがって、Pythonの動的型システムは常にダック型を使用します。

def f(x):
    x.Quack()

場合はf取得x支援Quack()、それは実行時にクラッシュしますない場合は、すべてが、大丈夫です。

しかし、アヒルのタイピングは動的なタイピングをまったく意味していません。実際、非常に人気のある完全に静的なアヒルのタイピングアプローチがあり、要件もありません。

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

この関数はx、できることを望んでいることをまったく伝えていないQuackため、代わりにコンパイル時に試行するだけで、すべてが機能する場合は問題ありません。


5
意味しませんでした:void f(IQuak x){x.Quak(); (K.Quackの代わりに)関数fのパラメーターがIQuack xではなくIQuack xであるため、非常に小さな間違いですが、修正する必要があるように感じました:)
dominicbri7

ウィキペディアによると、あなたの最後の例は「ダックタイピング」ではなく「構造タイピング」です。
ブリリアント14

:まあ、それはその議論のための個別のご質問がありますようですstackoverflow.com/questions/1948069/...
Brilliand

1
だからあなたが言ったことを理解すれば、ダックタイピングをサポートする言語とそれ以外の言語の違いは、ダックタイピングのそれだけで、関数が受け入れるオブジェクトのタイプを指定する必要はありませんか?def f(x)の代わりにdef f(IQuack x)
PProteus 2017年

124

簡単な説明(コードなし)

質問のセマンティクスの議論はかなり微妙です(そして非常に学術的です)が、ここに一般的な考えがあります:

アヒルのタイピング

(「それがアヒルのように歩き、アヒルのように鳴るなら、それはアヒルです。」- はい!しかし、それはどういう意味ですか?これは例によって最もよく示されます:

ダックタイピング機能の例:

私が魔法の杖を持っていると想像してください。それは特別な力を持っています。杖を振って「ドライブ」と言うと 車に、それでは、それは運転します!

それは他のものに働きますか?わからない:トラックで試してみる。うわー-それも運転する!次に、飛行機、電車、1ウッズで試してみます(これらは、人々がゴルフボールを「ドライブ」するために使用するタイプのゴルフクラブです)。彼らはすべて運転します!

しかし、それはティーカップでうまくいくでしょうか?エラー:KAAAA-BOOOOOOM!それはあまりうまくいきませんでした。====>ティーカップは運転できません!! えっ?

これは基本的にダックタイピングの概念です。これは、購入前の試用 システムです。うまくいけば、すべてが順調です。しかし、失敗した場合、手に残っている手榴弾のように、それはあなたの顔を爆破するでしょう。

つまり、オブジェクトの内容ではなく、オブジェクトが実行できる内容に関心があります

例:静的型付け言語

オブジェクトが実際に何であるを懸念していた場合、手品、事前設定された承認済みのタイプ(この場合は車)でのみ機能しますが、トラック、モペット、トゥクトゥクなど、運転できる他のオブジェクトでは失敗します。私たちの魔法の杖は車でのみ機能することを期待しているため、トラックでは機能しません。

言い換えれば、このシナリオでは、魔法は、オブジェクトがどのように非常に密接なルックスワンドである(それは車です?)ではなく、オブジェクトが何よりも行うことができます(例えば乗用車、トラックなどが運転できるかどうか)。

トラックを運転させる唯一の方法は、何らかの方法で魔法の杖をトラック車の両方に期待できるかどうかです(おそらく「共通のインターフェースを実装することによって」)。意味がわからない場合は、しばらくは無視してください。

まとめ:重要な持ち帰り

ダックタイピングで重要なのは、オブジェクト何であるかではなく、オブジェクトが実際に実行できることです


私はあなたが行動についてもっと気にするという前提が興味深いと思います、それは定義です。BDDがルビのような言語で成功していることは間違いありません。
パブロオルモスデアギレラ

27

タイプのオブジェクトを取得してBirdそのwalk()メソッドを呼び出す単純な関数を設計しているとしましょう。あなたが考えることができる2つのアプローチがあります:

  1. これは私の機能でありBird、のみを受け入れるか、コードがコンパイルされないことを確認する必要があります。誰もが私の機能を使用したい場合は、彼は私が唯一受け入れていることを認識しなければならないBirdのを
  2. 私の関数は何かobjectsを取得し、オブジェクトのwalk()メソッドを呼び出すだけです。だから、あればobjectwalk()、それは私の機能の意志が失敗したことができない場合には、正しいです。したがって、ここではオブジェクトがBird何か他のものであることは重要ではありません。できることは重要ですwalk() (これはダックタイピングです

アヒルのタイピングが役立つ場合があることを考慮する必要があります。たとえば、Pythonではアヒルのタイピングが頻繁に使用されます


便利な読書


1
素敵な説明、どんな利点がありますか?
sushil bharwani 2015年

2
この答えは単純明快で、おそらく初心者には最適です。(車や茶碗について語っていることや、それが移動した場合、その答え)それ以上の答えと一緒にこの答えを読む
DORRITO

18

ウィキペディアにはかなり詳細な説明があります:

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

ダックタイピングは、特定のクラスまたは特定のインターフェースの実装からの継承ではなく、オブジェクトの現在のメソッドとプロパティのセットが有効なセマンティクスを決定する動的タイピングのスタイルです。

重要な注意点として、ダックタイピングでは、開発者は実際の基本的なタイプではなく、消費されるオブジェクトの部分に関心を持っているようです。


13

古いイディオムを繰り返す答えがたくさんあります。

それがアヒルのように見え、アヒルのように鳴く場合、それはアヒル

次に、アヒルのタイピングで何ができるかについての説明、または概念をさらに難読化する例について詳しく説明します。

あまり助けにはなりません。

これは、私が見つけたアヒルのタイピングについてのわかりやすい英語の回答での最良の試みです。

ダックタイピングとは、オブジェクトがそれが何であるかによってではなく、何ができるかによって定義されることを意味します。

つまり、オブジェクトのクラス/タイプではなく、オブジェクトに対して呼び出すことができるメソッドと、オブジェクトに対して実行できる操作に関心があります。タイプではなく、何ができるかを気にします


3

アヒルのタイピング:

しゃべったり、アヒルのように歩くなら、それはアヒルです

これは通常、拉致と呼ばれます(拉致推論またはレトロダクションとも呼ばれ、より明確な定義だと思います)。

  • C(結論、私たちは何を参照してください)とR(ルール、私たちが知っている)、私たちが決める/受け入れ/前提とP(前提、プロパティを別の言葉で与えられた事実を)

    ...医療診断の基本

    カモと:C = 歩く、話すR = アヒルのようP = アヒルのよう

プログラミングに戻る:

  • オブジェクトoにはメソッド/プロパティmp1があり、インターフェース/タイプTにmp1が必要/定義されています

  • オブジェクトoにはメソッド/プロパティmp2が あり、インターフェース/タイプTにmp2が必要/定義されています

  • ...

だから、より簡単に受け入れることよりもMP1をあれば、いくつかの定義を満たしているように任意のオブジェクトに... MP1を表明して...、コンパイラ/ランタイムも大丈夫でなければなりませんoが型であるT

さて、上記の例はそうですか?Duckのタイピングは基本的にまったくタイピングではないのですか?それとも暗黙の型付けと呼ぶべきでしょうか?


3

言語自体を見ることは役立つかもしれません。それはしばしば私を助けてくれます(私はネイティブの英語を話す人ではありません)。

duck typing

1)この単語typingは、キーボードでタイプすることを意味するのではなく(私の頭の中で永続的なイメージがそうであったように)、それは「その種類の事物の種類は何か」を決定することを意味します

2)単語duckは、その決定がどのように行われるかを表します。「アヒルのように歩く場合、それはアヒルのようです」のように、それは一種の「緩い」決定です。それはアヒルかもしれないしそうでないかもしれないので、それは「ゆるい」ですが、それが実際にアヒルであるかどうかは関係ありません。重要なのは、カモでできること、カモが示す行動を期待できることです。私はそれをパン粉に食べさせることができます、そして、物事は私に向かって行くかもしれません、または私に向かって充電するか、または引き返すかもしれません...


2

私は一般的な答えを出していないことを知っています。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)"

引数の型を確認する必要はありません。<<(結果の場合)またはタイトルとアーティスト(曲の場合)をサポートする場合、すべてが機能します。そうでない場合、メソッドはとにかく例外をスローします(型をチェックした場合と同じように)。しかし、チェックがなければ、メソッドは突然より柔軟になります。配列、文字列、ファイル、または<<を使用して追加するその他のオブジェクトを渡すことができますが、これは機能します。


2

アヒルのタイピングはタイプのヒントではありません!

基本的に、「ダックタイピング」を使用するために、特定のタイプではなく、共通のインターフェースを使用して、より広い範囲のサブタイプ(継承についてではなく、サブタイプを意味するとき、同じプロファイルに適合する「もの」を意味する)をターゲットにします。

情報を保存するシステムを想像できます。情報を読み書きするには、何らかのストレージと情報が必要です。

ストレージのタイプには、ファイル、データベース、セッションなどがあります。

インターフェースは、ストレージタイプに関係なく利用可能なオプション(メソッド)を通知します。つまり、この時点では何も実装されていません。言い換えれば、インターフェイスは情報を格納する方法について何も知りません。

すべてのストレージシステムは、まったく同じメソッドを実装することにより、インターフェイスの存在を認識している必要があります。

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');

この例では、StorageコンストラクタでDuck Typingを使用します。

function __construct(StorageInterface $storage) ...

それが役に立てば幸い;)


2

アヒルのタイピング技術によるツリートラバーサル

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=" ")

0

動的型付け、静的型付け、アヒル型付けを混同するのは混乱していると思います。ダックタイピングは独立した概念であり、Goのような静的型付け言語でさえ、ダックタイピングを実装する型チェックシステムを持つことができます。型システムが(宣言された)オブジェクトのメソッドをチェックするが型はチェックしない場合、それはダックタイピング言語と呼ばれる可能性があります。


-1

私は自分の方法で有名な文を理解しようとします:「Pythonはオブジェクトが本当のカモであるかどうかを気にしません。気になるのは、オブジェクトが最初に「ガク」、次に「カモのよう」であるかどうかです。」

良いウェブサイトがあります。http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

著者は、ダックタイピングにより、独自の内部データ構造を持つ独自のクラスを作成できることを指摘しましたが、通常のPython構文を使用してアクセスします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.