0

デザインに問題があります。単一のオブジェクトまたはオブジェクトの反復可能オブジェクトのいずれかを受け入れるメソッドを作成したいと思います。たとえば、クラスDogがあるとします。

class Dog(object):
    """
    An animal with four legs that may slobber a lot
    """
    def __init__(self, name="Fido"):
       self.name = name

ここで、Dogクラスを使用するクラスがあるとします。DogWalkerと言います。

class DogWalker(object):
    """
    Someone who cares for Fido when Human Companion is not available
    """
    def __init__(self):
        self.dogs_walked = 0
        self.dogs_watered = 0

    def walk(self, dogs):
        """
        Take a dog for a walk
        """
        # This is not Pythonic
        if isinstance(Dog, dogs):
            # Walk a single dog
            pass
            self.dogs_walked +=1
        else:
            # walk lots of dogs
            pass


    def water(self, dogs):
        """
        Provide water to dogs
        """
        # More pythonic
        try:
            # Try to water single dog
            ...
            self.dogs_walked += 1
        except  AttributeError:
            # Try to water lots of dogs
            pass

上記の例では、walkとwaterの2つのメソッドを実装しました。水メソッドは、ダックタイピングを使用するという点でよりパイソン的です。ただし、もう少し話を進めたいと思います。さまざまな種類の動物に水をやることができる世話人クラスがあるとしましょう。

class CareTaker(object):
    """
    Someone who cares for things
    """
    def __init__(self):
        self.things_watered = 0

    def water(self, things):
        """
        Provide water to a thing
        """
        # Here is where I need help!
        # 1. I need to figure out if things is a single item or iterable
        # 2. If thing is a single item I need to figure out what type of thing a thing is
        # 3. If thing is an iterable, I need to figure out what type of things are in the iterable.
        pass

さて、私が思いついたのは、それぞれが自分自身に水をやる方法を知っているということです。そうすれば、世話人は物事を水法と呼ぶだけで済みます。例えば:

class CareTaker(object):
    """
    Someone who cares for things
    """
    def __init__(self):
        self.things_watered = 0

    def water(self, thing):
        """
        Provide water to a thing
        """
        result = thing.water()
        self.things_watered += 1
        return result

このようにコードを使用すると、次のようになります。

ct = CareTaker()
dog = Dog()
bird = Bird()
water_dog = ct.water(dog)
water_bird = ct.water(bird)

things = [dog, bird]

for thing in things:
    ct.water(thing)

他にもいくつかアイデアがありますが、具体的な設計アプローチをとる前に、そのような問題に直面した可能性のある他の人から意見を聞きたいと思います。あなたのアイデアの長所と短所もリストできれば。それはボーナスになります!ありがとう。

更新:これまでのところ、2つの等しく良い提案があるようです。

  1. 渡された引数の動作をテストします。たとえば、is_itereableメソッドを記述します。
  2. 位置引数を使用して、位置引数リスト内の項目のリストを反復処理します。

どちらが実際の問題に適しているかはまだわかりません。

4

2 に答える 2

6

*args「ワイルドカード」位置パラメータを使用できます。

def walk(self, *dogs):
    for dog in dogs:
        # handle each dog.

これを次のように呼びます。

owner.walk(onedog, anotherdog)

また

owner.walk(*listofdogs)
于 2012-09-26T14:10:04.273 に答える
0

この2つを組み合わせて実行することをお勧めします。犬、猫、鳥が同じメソッドを持つことができる限り、実際にどのオブジェクトを持っているかを気にせずにメソッド名を使用してください。(一般的な方法は動物のAPIです)。ただし、コンテナを渡す場合、各APIメソッドをその子のそれぞれに適用するコンテナクラスを偽造する問題が発生しない限り、これは機能しません。これは技術的には実行可能ですが、次の方がはるかに魅力的です。常にコンテナを期待するようにコードを記述し、単一のオブジェクトをリストに埋め込んで変換します。

class Caretaker(object):
    ...
    def water(self, things):
        if isinstance(things, animal): # actually only one: fix it
            things = [ things ]

        for thing in things:
            ...

animalこれは、派生元の親クラスdogとを前提としていますbirdthingsまたは、次のように、が反復可能かどうかを明示的に確認することもできます。

        if not isinstance(things, collections.Iterable):
            things = [ things ]

しかし、私は最初のアプローチを好みます。

于 2012-09-26T14:44:45.807 に答える