1

クラスがあるとしましょう:

注: これはダミー クラスのみです。

class C(object):
    def __init__(self):
        self.a = -10
        self.b = 5
        self.c = 2
    def modify(self, **kwargs):
        for keyword in kwargs:
            vars(self)[keyword] = kwargs[keyword]
        return(self)

そして、この変更メソッドを使用して、オブジェクトの値を変更します。

myclass = C()
myclass = myclass.modify(a=10)

しかし、元の値に基づいて値を変更したい場合は、次のように記述する必要があります。

myclass = C()
myclass = myclass.modify(a=myclass.a/10)

または:

myclass = myclass.modify(a=abs(myclass.a))

私の質問は、モジュールにグローバル変数を作成し、それをインポートして現在の値のプレースホルダーとして使用できる方法があるので、次の式を使用できるかどうかです。

from globvars import current

myclass = C()
myclass = myclass.modify(
    a=abs(current) % current ** 2,
    b=current//2,
    c=bool(current)
)

最初に、実行中の操作と値を格納するクラスを作成しようとしました。modify()最初にその変数をキーワードとして検索し、次に関数を実行します。実際には、current+10またはのような単純な状況でのみ機能しcurrent**2ます。しかし、私が気付いたときcurrent、たとえばhsba(current)カラーコンバーター)関数でこれを使用したいcurrent場合、他のオブジェクトに格納されているオブジェクトを指している場合、あきらめます。これをすべてのクラスに書き込むことはできません。使用する..

これに対する解決策はありますか?多分それはとても簡単です、私はそれを見ることができません:)

返信ありがとうございます!

4

4 に答える 4

0

私の意見では、あなたのデザインは貧弱ですが、を使用してこれを行うことができeval()ます。もちろん、それはあなたのデザインの匂いをさらに増すだけです. まだ...

class C(object):
    # ...
    def modify(self, **kwargs):
        for name, expr in kwargs.iteritems():
            setattr(self, name, eval(expr, vars(self)))

obj = C()
obj.modify(a="a+2", b="b*42")

欠点は、式を文字列として渡す必要があることです。また、この単純な実装では、式のインスタンスで定義された値のみを使用できます (たとえば、クラス属性、親クラスの属性、またはグローバルにアクセスすることはできません)。vもちろん、適切な順序でディクショナリを構築することにより、クラス属性またはグローバル、さらには親クラスを使用する機能を追加できます。

def modify(self, **kwargs):
    vardict = {}   # allow globals and self attributes to be used in expressions
    vardict.update(globals())
    vardict.update(vars(self))
    for name, expr in kwargs.iteritems():
        value = eval(expr, v)
        setattr(self, name, eval(expr, vardict))
        vardict[name] = value

現在の値を保持する変数が必要な場合はcurrent、これを使用できます (処理される属性ごとに変更する必要があるため、ループ内で)。

v["current"] = getattr(self, name, None)

ここでの最大の欠点の 1 つは、呼び出し元のスコープから変数に簡単にアクセスできないことです。ただし、スタック フレームから変数を掘り出すことはできると思います。または、発信者にそれらを文字列に補間させます...二重うーん。

私の意見では、Morphynの答えはそれを行う適切な方法です。ラムダはほとんど複雑ではありません

于 2013-05-03T15:24:41.670 に答える
0

これが実用的なソリューションです。完全ではなく、かなり悪いデザインの選択でいっぱいですが、役に立てば幸いです.

class Expr(object):

    def __init__(self, op, left, right):
        self.op = op
        self.left = left
        self.right = right

    def __call__(self, current):
        l = self._replace_current(self.left, current)
        r = self._replace_current(self.right, current)
        return self._do_operation(l, r)

    def _replace_current(self, val, current):
        if val == 'current':
            return current
        elif isinstance(val, Expr):  # recurse
            return val(current)
        else:
            return val

    def _do_operation(self, l, r):
        if self.op == '+':
            return l + r
        elif self.op == '*':
            return l * r
        elif self.op == '-':
            return l - r

    def __add__(self, other):
        return self._left_op('+', other)

    def __radd__(self, other):
        return self._right_op('+', other)

    def __mul__(self, other):
        return self._left_op('*', other)

    def __rmul__(self, other):
        return self._right_op('*', other)

    def __sub__(self, other):
        return self._left_op('-', other)

    def __rsub__(self, other):
        return self._right_op('-', other)

    def _left_op(self, op, other):
        if isinstance(other, Current):
            return Expr(op=op, left=self, right='current')
        else:
            return Expr(op=op, left=self, right=other)

    def _right_op(self, op, other):
        if isinstance(other, Current):
            return Expr(op=op, left='current', right=self)
        else:
            return Expr(op=op, left=other, right=self)


class Current(Expr):

    def __init__(self):
        super(Current, self).__init__(None, None, None)

    def __call__(self, current):
        return current

    def _left_op(self, op, other):
        return Expr(op=op, left='current', right=other)

    def _right_op(self, op, other):
        return Expr(op=op, left=other, right='current')


current = Current()


class YourObj(object):

    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __call__(self, **kw):
        for key, val in kw.iteritems():
            # You should probably make sure it is actually an attribute of YourObj
            if isinstance(val, Expr):
                current = self.a
                new_val = val(current)
                setattr(self, key, new_val)
            else:
                setattr(self, key, val)

そして、次のようなことができます:

obj = YourObj(a=4, b=5)
obj(a=current - 4 + current * current)

これは基本的に、Python の数学演算に組み込まれた式インタープリターです。

current(+ のような)に対して演算を使用するときはいつでも、( andをExprオーバーライドするため) が返され、これがどの演算であるか、および各オペランドが何であるかを登録します。これらの式は入れ子にすることができるので、 と言えばを返します。__add____radd__current + 4 - currentExpr(op='-', left=Expr(op='+', left='current', right=4), right='current')

式は、関数のように呼び出し、'current' を置き換える値を渡すことで評価できます。式を評価すると、次のようになります。

  • 'current' のすべての出現箇所を渡された値で置き換えます
  • ネストされた関数を再帰的に評価する
  • 式全体の最終結果を返す

を実行するobj(a=current + 4)と、 の__call__メソッドYourObjが呼び出されます。の結果の式を評価し、current + 4に格納しaます。

これがより明確になることを願っています。混乱を避けるために、「現在」の名前を変更する必要があるかもしれません。

于 2013-05-03T22:51:19.570 に答える
0

これは私の古い解決策でした..(一種の、これはダミーバージョンです

class __current__(object):
    def do(self, e, v = None):
        c = __current__()
        c.exp = e
        if v is not None:
            c.val = v
        return(c)
    def __abs__(self):
        return(self.do(abs))
    def __rpow__(self, v):
        return(self.do(pow, v))

current = __current__()

class C(object):
    def __call__(self, **kwargs):
        for keyword, value in kwargs.iteritems():
            try:
                expression = value.exp
                try:
                    value = expression(vars(self)[keyword], value.val)
                except AttributeError:
                    value = expression(vars(self)[keyword])
            except AttributeError:
                value = value
            setattr(self, keyword, value)

そして使用法:

MyObj = C()
MyObj(a = -2)
MyObj(a = abs(current))
MyObj(a = 2 ** current)
于 2013-05-04T00:01:36.673 に答える