5

クライアントコードによって実装される「インターフェース」があります。

class Runner:
    def run(self):
        pass

runは一般に を返す必要docutils nodeがありますが、最も一般的なケースはプレーン テキストであるため、呼び出し元はrun文字列を返すことができます。これは を使用してチェックtype()され、 に変換されますnode

ただし、私が「Pythonic」を理解する方法は、これは「Pythonic」ではありません。これはtype()、何かをチェックしても、型のように「振る舞う」ことによって型に「なる」ことができないためです。つまり、「Pythonic」コードはダックタイピングを使用する必要があります。

私は考慮した

def run_str(self):
    pass

def run_node(self):
    return make_node(self.run_str())

しかし、あまり面白くない戻り値の型が名前に含まれているため、私はこれを気にしません。それは気を散らすものです。

私が見逃したアイデアはありますか?また、「悪い」システムで将来遭遇する可能性のある問題はありますか (多かれ少なかれ安全に思えます)?

4

5 に答える 5

5

これは少し欺瞞的な例だと思います。あなたが述べていないことがあります。あなたが「インターフェースを持っている」と言うとき、それは、オブジェクトを受け取り、そのrunメソッドを呼び出すコードがあるということを意味していると思います。

メソッドを呼び出す前にそのオブジェクトの型をテストしていない場合は、runダックタイピングを使用していることになります。(この場合、runメソッドがあれば、それは です。)メソッドを持つオブジェクトに対してorをRunner使用しない限り、あなたはPythonic です。typeisinstancerun

プレーンな文字列を受け入れるか、ノード オブジェクトのみを受け入れるかという問題は、微妙に異なる問題です。文字列とnodeオブジェクトは、おそらくまったく同じインターフェースを実装していません! 文字列は基本的にのように鳴かないnodeので、同じように扱う必要はありません。これは、やってくる象のようなものです。アヒルのように鳴き声を上げたい場合は、象にテープ プレーヤーを与え、最初にそれを使用するように象を訓練する必要があります。

したがって、これはもはや「ダックタイピング」の問題ではなく、インターフェイスの設計の問題です。インターフェイスをどの程度厳密にするかを決定しようとしています。

run答えを出すために、このレベルでは、 がオブジェクトを返すと仮定するのが最も Pythonic だと思いnodeます。isinstanceそれを使用したりtypeテストしたりする必要はありません。オブジェクトのふりをするだけでnode、インターフェイスを使用しているプログラマーが間違って例外を見つけた場合、docstring を読み取ってrun、オブジェクトを渡す必要があることを伝える必要がありnodeます。

次に、文字列、または文字列のように鳴くものも受け入れたい場合は、そうすることができます。また、文字列はかなりプリミティブな型であるため、使用するのは不適切ではないと思いますisinstance(obj, basestring)(ただし、Unicode 文字列などを拒否するためではありません) type(obj) == str本質的に、これはあなたがあなたのプログラムの怠惰なユーザーに対して非常に寛大で親切であることです。ゾウやアヒルのように鳴くものを受け入れることで、あなたはすでに上を行き来しています。

(より具体的には、これは、iterジェネレーターとシーケンスの両方を受け入れたい関数の先頭で引数を呼び出すのと少し似ていると思います。)

于 2011-08-18T04:50:17.920 に答える
2

特に単純な操作だけが発生する場合は、各タイプを処理するためのメソッドを必ずしも持つ必要はありません。一般的な Pythonic アプローチは、次のようなことです。

def run(self):
    try:
        ...assume it's a str   
    except TypeError:
        ...oops, not a str, we'll address that

これは、許可よりも許しを求めやすい (EAFP)スタイルのコーディングに従います。これは、一般に、より高速で単純です。

于 2011-08-18T04:21:58.317 に答える
1

エラーと例外を確認してください。次のようなことができます。

def run(self,arg):
    try:
        return make_node(arg)
    except AlreadyNodeError:
        pass

make_node 関数内で、引数が既にノードである場合、AlreadyNodeError を発生させます。

于 2011-08-18T04:21:40.403 に答える
1

を使用type()して変数の型を検出することは、実際には悪い習慣です。オブジェクトが目的の型から継承することを許可しないためです(strあなたの場合)。より良い方法は、次を使用することisinstance()です:

if isinstance(my_var, str):
    my_code_here()

また、これを行うPythonicの方法は、あなたが言及したようにダックタイピングになります./ブロックにコードを入れてみませんtryexcept? そのため、値が期待どおりに動作しない場合にのみ、例外がキャッチされます(アヒルのように鳴いて歩く場合は、アヒルです)。

于 2011-08-18T04:27:02.810 に答える
0
class Node(object):
  def __new__(cls, contents):
    return contents if isinstance(contents, cls) else object.__new__(cls)
  def __init__(self, contents):
    # construct from string...

class Manager(object):
  def do_something(self, runner, *args):
    do_something_else(Node(runner(*args)))

ランナーがノードを返すか文字列を返すかは問題ではありません。

于 2011-08-18T04:55:29.203 に答える