是否可以在python中创建一个变量作为占位符的“当前”值?

时间:2013-05-03 14:09:28

标签: python oop class variables placeholder

假设我们有一个班级:

注意:这只是一个虚拟类。

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+10current**2。 但是当我意识到,我希望使用此current例如hsba(current)颜色转换器)函数,其中current指向存储在其中的对象另一个对象,我只是放弃了,我不能把它写给我将要使用的每个类......

有解决方案吗?也许这很容易,我只是看不到它:)

提前感谢您的回复!

4 个答案:

答案 0 :(得分:0)

您的modify方法可以使用要修改的属性的名称,以及获取该属性的当前值并返回其新计算值的函数。然后你可以做类似的事情:

def compute_new_value(current):
    new_value = abs(current) % current ** 2
    return new_value

myclass = C()
myclass.modify('a', compute_new_value)

对于简单的情况,lambda使其不那么冗长:

myclass.modify('a', lambda cur: cur + 4)

你的班级:

class C(object):
    [...]
    def modify(self, attr_name, func):
        cur_value = getattr(self, attr_name)
        new_value = func(cur_value)
        setattr(self, attr_name, new_value)

编辑:我可能错过了一些东西。由于您正在编写myclass = myclass.modify...modify方法是否应该返回对象的副本

答案 1 :(得分: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)

这里最大的缺点之一就是你无法轻易地从调用者范围访问变量,尽管你可以将它们从堆栈框架中挖出来,我猜...呃。或者让调用者将这些插入到字符串中...... double ugh。

在我看来,Morphyn的答案是正确的方法。 lambda很难复杂

答案 2 :(得分: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上使用某个操作(例如+)时,它将返回Expr(因为它会覆盖__add____radd__),这将记录此操作是什么,它的每个操作数是什么。这些表达式可以嵌套,因此如果您说current + 4 - current,它将返回Expr(op='-', left=Expr(op='+', left='current', right=4), right='current')

然后可以通过将其称为函数并将其传递给应替换“current”的值来计算表达式。评估表达式时,它将:

  • 用传递的值
  • 替换'current'的所有出现
  • 递归评估嵌套函数
  • 返回整个表达式的最终结果

执行obj(a=current + 4)时,会调用__call__的{​​{1}}方法。它将评估YourObj的结果表达式并将其存储在current + 4

我希望这更清楚。也许我应该重命名一些'当前',以减少它的混乱。

答案 3 :(得分: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)