0

クラス ( )のパラメータに基づいて、特定の関数セット (この場合は 、 、および ) を割り当てたいクラス ( )がありnodeます。a1a2b1b2operatingMode

状況は、多くの異なる動作モードを持つモーターを持っているということです。各動作モードでは、特定の機能を実行できますが、他の機能は実行できません。さまざまなモードへの関数の割り当ては、各操作モードのクラスを作成するのに適していない方法で行われます。

以下は私の解決策ですが、うまくいきません。

何かご意見は?

def a1(self):
    return 'a1'

def a2(self):
    return 'a2'

def b1(self):
    return 'b1'

def b2(self):
    return b2




class node(object):
    def __init__(self,operatingMode):
    self.operatingMode=operatingMode

    if self.operatingMode=='A':
        self.a1function=a1
        self.a2function=a2
        print 'Operating Mode \'A\' functions loaded'

    if self.operatingMode=='B':
        self.b1function=b1
        self.b2function=b2
        print 'Operating Mode \'B\' functions loaded'

    def setOperatingMode(self,operatingMode):
        self.operatingMode=operatingMode
        self.__init__(self,operatingMode)

端末でこれを実行すると呼び出すことができますが、elbow を 2 回宣言する必要があります。

In [65]: elbow=node('A')
Operating Mode 'A' functions loaded

In [66]: elbow.a1function(elbow)
Out[66]: 'a1'

実行しようとするelbow.setOperatingMode('B')とエラーが発生します。

4

4 に答える 4

2

types.MethodTypeと の使用__getattr__:

import types

def a1(self):
    return 'a1'

def a2(self):
    return 'a2'

def b1(self):
    return 'b1'

def b2(self):
    return 'b2'

class Node(object):
    def __init__(self, operatingMode):
        self.operatingMode = operatingMode
    def __getattr__(self, attr):
        if self.operatingMode=='A':
            if attr == 'a1function':
                return types.MethodType(a1, self)
            if attr == 'a2function':
                return types.MethodType(a2, self)

        elif self.operatingMode=='B':
            if attr == 'b1function':
                return types.MethodType(b1, self)
            if attr == 'b2function':
                return types.MethodType(b2, self)
        else:
            raise AttributeError()

それで

elbow = Node('A')
print(elbow.a1function())
elbow.operatingMode = 'B'
print(elbow.b2function())

収量

a1
b2
于 2013-04-03T21:31:10.383 に答える
1

おそらく、デコレータを使用する方がクリーンな方法です。これにより、魔法checkModeが回避されます。__getattr__type.MethodType

def checkMode(mode):
    def deco(func):
        def wrapper(self):
            if self.operatingMode == mode:
                return func(self)
            else:
                raise TypeError('Wrong operating Mode')
        return wrapper
    return deco

class Node(object):
    def __init__(self, operatingMode):
        self.operatingMode = operatingMode

    @checkMode('A')
    def a1(self):
        return 'a1'

    @checkMode('A')
    def a2(self):
        return 'a2'

    @checkMode('B')
    def b1(self):
        return 'b1'

    @checkMode('B')
    def b2(self):
        return 'b2'

上記のコードを使用すると、次のことができます。

elbow = Node('A')
print(elbow.a1())
# a1

knee = Node('A')
print(knee.a1())
# a1

elbow.operatingMode = 'B'
print(knee.a1())  # knee is still in operatingMode A
# a1

print(elbow.b2())
# b2

elbow.a1()
# TypeError: Wrong operating Mode

説明:

デコレータの構文は次のように機能します。

@deco
def func(): ...

と同等です

def func(): ...
func = deco(func)

上記checkModeは、デコレータを返す関数decoです。 deco次に、メソッドa1a2などを装飾して、

a1 = deco(a1)

したがって、a1は に渡される関数decoです。deco(a1)は、一般に と呼ばれる新しいメソッドを返しますwrappera1この新しいメソッドは、ステートメントによって割り当てられa1 = deco(a1)ます。メソッドa1も同様wrapperです。したがって、 を呼び出すとelbow.a1()、 のコードwrapperが実行されます。

于 2013-04-03T21:50:35.707 に答える
1

このコメントに応えて:

これはモーター制御用なので、オーバーヘッドを制限しようとしています...動作モードは、個々のコマンドが呼び出されるよりもはるかに頻繁に変更されます。

Python インスタンスはクラスを変更できます。ifこれを使用して、 -clause を使用してモードを確認する必要なく、動作モードを変更できます。

class Base(object):
    # Put any methods shared by ANode and BNode here.
    pass

class ANode(Base):
    def a1(self):
        return 'a1'

    def a2(self):
        return 'a2'

class BNode(Base):
    def b1(self):
        return 'b1'

    def b2(self):
        return 'b2'


elbow = ANode()
print(elbow.a1())
# a1

knee = ANode()
print(knee.a1())
# a1

elbow.__class__ = BNode
print(knee.a1())
# a1
print(elbow.b2())
# b2

elbow.a1()
# AttributeError: 'BNode' object has no attribute 'a1'

良い面としては、これは私が投稿した最速の提案です。if上記のコードにはステートメントがないことに注意してください。クラスが変更されると、使用可能なすべてのメソッドが「即座に」変更されます。これは、純粋に通常の Python メソッド呼び出しのセマンティクスによるものです。

Nodeがデコレータ ソリューションのように定義されている場合、

In [33]: elbow = Node('A')

In [34]: %timeit elbow.a1()
1000000 loops, best of 3: 288 ns per loop

一方、kneeを使用して定義されている場合ANode

In [36]: knee = ANode()

In [37]: %timeit knee.a1()
10000000 loops, best of 3: 126 ns per loop

したがって、このソリューションは、デコレータ ソリューションよりもメソッドの呼び出しが 2 倍以上高速です。

スイッチング速度は同等です:

In [38]: %timeit elbow.operatingMode = 'B'
10000000 loops, best of 3: 71.7 ns per loop

In [39]: %timeit knee.__class__ = BNode
10000000 loops, best of 3: 78.7 ns per loop

警告: 私が投稿したすべての解決策を悩ませようとしている 1 つのことは、切り替え後使用可能なメソッドが変更されることです。つまり、これらのクラスを使用してプログラミングする場合、使用可能なメソッドを知る前に、インスタンスの状態を追跡する必要があります。それは厄介です。

まったく同じインターフェイス (すべて同じ属性名とメソッド名) を持ち、これらのメソッドの定義だけを変更する (モードまたはクラスが変更された場合)場合ANode、プログラムははるかに単純になります。BNode


このコメントについて:

約100の機能と7つの操作モードがあります。これらの機能のうち、約 10 はすべての動作モードで共有され、75 は複数のモードで共有され、15 は特定のモード専用です。問題は、75 がモードに適切に割り当てられていないことです。モード 1、4、および 7 にあるものもあれば、2、4、5、および 7 にあるものもあれば、1 および 5 にあるものもあります。

クラスの外側でメソッドを定義してから、次のようにモードベースのクラスに「接続」できます。

def a1(self):
    return 'a1'

def a2(self):
    return 'a2'

def b1(self):
    return 'b1'

def b2(self):
    return 'b2'

class Base(object):
    # Put the 10 methods share by all modes here
    def common1(self): 
        pass

class ANode(Base):
    a1 = a1
    a2 = a2

class BNode(Base):
    b1 = b1
    b2 = b2

class CNode(Base):
    a1 = a1
    b2 = b2
于 2013-04-03T22:02:41.857 に答える
0

あなたのデザイン全体は非常に奇妙です。おそらく一歩下がって、何をしようとしているのかを説明して、誰かがより良いデザインを手伝ってくれるようにする必要があります.

ただし、設計を機能させたいだけの場合、現在のコードには 2 つの問題があります。

self.a1function = a1

これはself.a1function、バインドされたメソッドではなく、通常の関数に設定されます。次のようにバインドされたメソッドを明示的に作成できます。

self.a1function=types.MethodType(a1, self, self.__class__)

またはa1function、 のラッパーになるように設定することもできますa1。または、より単純に、ラッピングを動的に行います。つまり、バインドされたメソッド性をクロージャーで偽装できるため、おそらくより読みやすくなります。

def __getattr__(self, attr):
    if attr == 'a1function' and self.operating_mode == 'A':
        return lambda: a1(self)

その間:

bow.setOperatingMode('B') を実行しようとすると、エラーが発生します。

「エラーが発生する」と言うだけでなく、トレースバック、または少なくともエラー文字列を投稿する必要があります。この場合、エラーの内容が非常に明確に示されるため、推測する必要はありません。

TypeError: __init__() takes exactly 2 arguments (3 given)

問題は、次の行にあります。

self.__init__(self,operatingMode)

self2 回合格しています。メソッドを呼び出すオブジェクトであり、最初のパラメーターでもあります。

いずれにせよ、別のメソッドから呼び出す__init__のは悪い考えですが、本当にしたい場合は、他のメソッドを呼び出すのと同じです:

self.__init__(operatingMode)
于 2013-04-03T21:31:06.723 に答える