繁体   English   中英

类似Python的数字类会记住算术运算吗?

[英]Python number-like class that remembers arithmetic operations?

我想知道是否存在允许我做这样的事情的python模块:

x = MagicNumber()
x.value = 3
y = 2 * (x + 2) ** 2 - 8
print y   # 42
x.value = 2
print y   # 24

因此, MagicNumber将实现所有特殊的运算符方法,并且它们都会返回MagicNumber的实例,同时跟踪执行的操作。 有这样的课吗?

编辑:澄清

我想在一个模块中使用它,该模块应该记住用户希望执行的某些任意计算的许多参数。 因此,用户将设置参数,然后使用它们来生成结果。 然后如果他决定改变参数,那么改变会立即反映在他的结果中。 因此,只有一个参数实例的非常简化的使用会话将如下所示:

p = MyParams()
p.distance = 13.4           # I use __getattr__ and __setattr__ such that
p.speed = 3.14              # __getattr__ returns MagicNumber instances
time = p.distance / p.speed

编辑2:更多澄清

好的,我会从一开始就做我应该做的。 我会提供上下文。

您是一名工程师,您将制作一份LaTeX文档,详细说明某些原型小工具的工作原理和属性。 对于不同的原型,这是一项重复的任务。 你写了一个小的LaTeX python接口。 对于每个原型,您创建一个生成必需文档的python模块。 在其中输入LaTeX代码,同时根据需要计算变量,以便计算在上下文中。 过了一会你就发现了两个问题:

  1. 变量和参数的数量使得本地人变得混乱,变量名称很难记住。 您应该将它们分组到类别中以跟踪它们。
  2. 您有时需要重做相同的计算,该计算分布在最后几章和十几行中,其中一个或多个参数已更改。 您应该找到一些方法来避免代码重复。

出于这个问题出现了原始问题。

像这样的东西?

import operator

MAKE_BINARY  = lambda opfn : lambda self,other : BinaryOp(self, asMagicNumber(other), opfn)
MAKE_RBINARY = lambda opfn : lambda self,other : BinaryOp(asMagicNumber(other), self, opfn)

class MagicNumber(object):
    __add__  = MAKE_BINARY(operator.add)
    __sub__  = MAKE_BINARY(operator.sub)
    __mul__  = MAKE_BINARY(operator.mul)
    __radd__ = MAKE_RBINARY(operator.add)
    __rsub__ = MAKE_RBINARY(operator.sub)
    __rmul__ = MAKE_RBINARY(operator.mul)
    # __div__  = MAKE_BINARY(operator.div)
    # __rdiv__ = MAKE_RBINARY(operator.div)
    __truediv__ = MAKE_BINARY(operator.truediv)
    __rtruediv__ = MAKE_RBINARY(operator.truediv)
    __floordiv__ = MAKE_BINARY(operator.floordiv)
    __rfloordiv__ = MAKE_RBINARY(operator.floordiv)

    def __neg__(self, other):
        return UnaryOp(self, lambda x : -x)

    @property
    def value(self):
        return self.eval()

class Constant(MagicNumber):
    def __init__(self, value):
        self.value_ = value

    def eval(self):
        return self.value_

class Parameter(Constant):
    def __init__(self):
        super(Parameter, self).__init__(0.0)

    def setValue(self, v):
        self.value_ = v

    value = property(fset=setValue, fget=lambda self: self.value_)

class BinaryOp(MagicNumber):
    def __init__(self, op1, op2, operation):
        self.op1 = op1
        self.op2 = op2
        self.opn = operation

    def eval(self):
        return self.opn(self.op1.eval(), self.op2.eval())


class UnaryOp(MagicNumber):
    def __init__(self, op1, operation):
        self.op1 = op1
        self.operation = operation

    def eval(self):
        return self.opn(self.op1.eval())

asMagicNumber = lambda x : x if isinstance(x, MagicNumber) else Constant(x)

在这里,它正在行动:

x = Parameter()
# integer division
y = 2*x*x + 3*x - x//2

# or floating division
# y = 2*x*x + 3*x - x/2

x.value = 10
print(y.value)
# prints 225

x.value = 20
print(y.value)
# prints 850

# compute a series of x-y values for the function
print([(x.value, y.value) for x.value in range(5)])
# prints [(0, 0), (1, 5), (2, 13), (3, 26), (4, 42)]

你可以用一个用Python编写的计算机代数系统来表达同情 ,试一试。

例如

>>> from sympy import Symbol
>>> x = Symbol('x')
>>> y = 2 * (x + 2) ** 2 - 8
>>> y
2*(x + 2)**2 - 8
>>> y.subs(x,3)
42
>>> y.subs(x,2)
24

这不是一个function吗? 这可能听起来像一个简单的答案,但我的意思是真诚的。

def y(x):
    return 2 * (x + 2) ** 2 - 8

你不是在想这个错误的方向吗?

解决澄清问题:

class MyParams():
    distance = 0.0
    speed = 0.0
    def __call__(self):
        return self.distance / self.speed

p = MyParams()
p.distance = 13.4            # These are properties
p.speed = 3.14               # where __get__ returns MagicNumber instances
time = p()  # 4.26
p.speed = 2.28
time = p()  # 5.88

我想我更赞成这种类型的解决方案,尽管我看到了sympy模块的好处。 我想是偏好。

>>> magic = lambda x: eval('2 * (x + 2) ** 2 - 8')
>>> magic(2)
24
>>> magic(3)
42
>>> magic = lambda x: eval('x ** 4')
>>> magic(2)
16
>>> magic(3)
81

我认为困难在于“如何保持运营商的优先权”而不是实施一个班级。

我建议看一下可能有助于摆脱优先问题的另一种符号(如反向波兰表示法 )......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM