Pythonでduck typing(ダックタイピング)を実装する方法

スポンサーリンク

Duck typingはDynamic Programmingのバリエーションで、型チェックにabductive reasoningの形式を採用しています。

この記事では、ダックタイピングの主な直感と、pythonでのダックタイピングの例に焦点を当てます。

スポンサーリンク

PythonのDuck Typingとは?- 帰納的推論

アヒルという言葉は、間違いなく有名なフレーズに由来しています。

“If it walks like a duck, and it quacks like a duck, then it is probably be a duck.”

このフレーズの最も重要な点は、我々はオブジェクトがアヒルであるかどうかを実際に知っているのではなく、オブジェクトがアヒルであることを振る舞いのリストから推測/還元していることです。

2つのオブジェクトが同じかどうかを内部的にチェックしているのではなく、2つのオブジェクトを一致させるために既知の外部的な振る舞いを使っていることを観察することが重要です。

このような推論は、コンピュータサイエンスの領域にも転用可能です。

動的言語では、明示的な型チェックは行われない。

しかし、関数の振る舞いが適切であることを確認するためのある種のユースケースでは、入力の型を検証することが重要になる。

このような場合、動的型付けでは様々な制約や設計上の問題が発生するため、アヒル型付けが持ち込まれた。

Duck Typingでは、オブジェクトそのものよりも、オブジェクトの内部で定義されているメソッド(振る舞い)を重視します。

オブジェクトが必要なメソッドを持っていれば、そのオブジェクトは通過することができる。

この概念を理解するために、例を見てみましょう。

Duck Typing の例

アヒル、ガチョウ、ネコという異なる動物を表す3つのクラスを定義します。

これらはすべて異なる音を出す。

アヒルとガチョウは「クワッ」と鳴き、ネコは「ニャー」と鳴く。

そして、動物を取り込んで、その説明をクワックという音とともに表示する関数quack()を定義します。

quack()のメソッドを持たない動物がこの関数に渡されると、変数の型が間違っている(アヒルのテストに失敗した)ことを示すエラーが発生することは明らかです。

# Define the three classes
 
class Duck:
  def quack(self):
    print("I am a duck and I quack.")
 
class Goose:
  def quack(self):
    print("I am a goose and I quack.")
 
class Cat:
  def meow(self):
    print("I am a dog and I meow.")
 
# Define the method
def quack(animal):
  animal.quack()

3匹の動物を渡し、それぞれに鳴き声を聞かせる。

DuckとGooseが鳴いたのに対して、Catは鳴くことができないので、エラーを投げます。

quack(Duck())
quack(Goose())
quack(Cat())
class Squares:
  def __init__(self, l=0, u=-1):
    self.u = u
    self.n = l
  def __iter__(self):
    return self
  def __next__(self):
    if self.n < self.u:
      s = self.n ** 2
      self.n += 1
      return s
    else:
      raise StopIteration

したがって、オブジェクトの型を外部でチェックしなくても、pythonはメソッドの互換性をチェックすることで、このオブジェクトがこの関数をサポートしていないことを知っていることがわかります。

ダックタイピングの実用例

duck typingの最もよく使われる例の1つは、pythonのiterationです。

Pythonで反復可能なオブジェクトごとにforループを書くにはどうしたらいいか考えたことがありますか?あるいは実際、何がオブジェクトを反復可能にするのでしょうか?ループはリスト、numpyの配列、ジェネレータ関数、Tensorflow/PyTorchのデータローダなどで使うことができます。

ここで登場するのがアヒルの型付けです。

これらのオブジェクトがどんなに用途が違っても、ダックタイピングのおかげで平等に扱われます。

反復処理を行うためには、クラスは必ず _iter(), _next() という関数を持っていなければなりません。

Pythonはこれらのクラスを強くタイプチェックしないので、ますます柔軟になっています。

Pythonの反復処理中に呼び出されるメソッドである⾳⾳⼭() と⾳⾳⾳⾳()も定義しています。

for i in Squares(1, 4):
  print(i)
1
4
9
Quack Error - duck typing in Python
Quack Error

まとめ

Pythonのダックタイピングのサポートにより、Pythonの基本関数とユーザー定義クラスとのシームレスな統合が可能になりました。

また、2つの異なるクラス間の相互作用と統合を可能にします。

Python のイテレータの例を見てきましたが、このコンセプトは len() にも適用でき、そのオブジェクトの中に _len___path() メソッドが定義されているかを duck checks しています。

Pythonの他の様々なメソッドを試すことができ、Pythonがいかに柔軟であるかを知ることができます。

参考文献

  • Yong CuiによるMediumの記事
  • Opensourceの記事
タイトルとURLをコピーしました