ダックタイピングの原則は、あなたが持っているオブジェクトのタイプを気にする必要はないことを示しています-あなたが必要なアクションをあなたのobject。このため、
isinstance
キーワードは推奨されません。 -- 定義
以下のスニペット(関数)group_tweets_by_state
では、ダックタイピングの定義に従って、オブジェクトsetdefault
を追加することにより、アクション_Tweet
がオブジェクトtweets_by_state
に対して実行されます。
def group_tweets_by_state(tweets):
tweets_by_state = {}
USA_states_center_position = {n: find_center(s) for n, s in us_states.items()}
for Tweet in tweets: # tweets are list of dictionaries
if hassattr(Tweet, 'setdefault'): # Tweet is a dictionary
state_name_key = find_closest_state(Tweet, USA_states_center_position)
tweets_by_state.setdefault(state_name_key, []).append(Tweet)
return tweets_by_state
私の理解は、関数hasattr(Tweet, 'setdefault')
は型チェックTweet
で、アヒルのタイピングスタイルで<class 'dict'>
タイプであること、before追加。
私の理解は正しいですか?関数group_tweets_by_state
はダックタイピングに従っていますか?
Tweet
がディクショナリのすべてのメソッド/プロパティを提供することを保証しないため、Tweet
がディクショナリであることを確認するhassattr(Tweet, 'setdefault')
のようなテストは良いテストではありません。したがって、_Tweet.setdefault
_が_find_closest_state
_によって呼び出される唯一のメソッドではない限り(これはありそうもないことです)、このテストは十分に厳密ではありません。一方、isinstance(Tweet, dict)
のようなテストは、他の辞書のような構造の使用を禁止しているため、厳密すぎます。これは、正確にダックタイピングの概念です。
あなたの例では、要件は実際にTweet
がディクショナリではないこと、要件は_find_closest_state
_がツイートを処理できることであり、実際のタイプとは関係なく、ツイートから呼び出されます。次のソリューションは、_find_closest_state
_内のどのメソッドが使用されているかを正確に知る必要なく、一般的な方法でこれを処理します。
_def group_tweets_by_state(tweets):
tweets_by_state = {}
USA_states_center_position = {n: find_center(s) for n, s in us_states.items()}
for Tweet in tweets: # a Tweet should behave like a dictionary
try:
state_name_key = find_closest_state(Tweet, USA_states_center_position)
tweets_by_state.setdefault(state_name_key, []).append(Tweet)
except (AttributeError, TypeError):
pass
return tweets_by_state
_
コードはAttributeError
をチェックします。これは、_find_closest_state
_がTweet
で提供されていないメソッドを呼び出したときに取得する例外であるためです。また、TypeError
もチェックします。これは、辞書以外で_Tweet["abc"]
_を呼び出したときに得られるものだからです。 _find_closest_state
_の内部実装方法によっては、他の例外を追加する必要がある場合がありますが、人工的な制約を追加しないでください。
そして、それがダックタイピングを実際に適用する方法です-必要なアクションを実行できるかどうかをテストすることによってのみ、渡されたオブジェクトのタイプについて仮定を行わないことによって(ここでは、上記の例外の1つを取得せずに_find_closest_state
_を呼び出します) )。
まず、ダックタイピングが良いことだと誰もが認めているわけではないことは言うまでもありません。ダックタイピングは、コードのデバッグが困難なエラーを引き起こしがちですが、使用方法は非常に柔軟です。
ダックのタイピングはオブジェクトを受け取り、そのオブジェクトに対して実行したいことを行います。 .write()
をオンにしたいオープンファイルオブジェクトが必要な場合は、それを実行します。オブジェクトにそのメソッドがないために例外がスローされる場合は、非ダックを渡しました。あなたのせい。 .write()
があるために機能するまったく異なる種類のオブジェクトを渡した場合、それがダックタイピングの利点です。
そのため、コードは、コメントが言うようにtweets
がディクショナリのリストであると単純に想定し、それをチェックするために問題に行かない場合、「ダックタイピング」を使用します。
def group_tweets_by_state(tweets):
tweets_by_state = {}
USA_states_center_position = {n: find_center(s) for n, s in us_states.items()}
for Tweet in tweets: # tweets are list of dictionaries
state_name_key = find_closest_state(Tweet, USA_states_center_position)
tweets_by_state.setdefault(state_name_key, []).append(Tweet)
return tweets_by_state