类似Python数字的类,能够记住算术运算?

类似Python数字的类,能够记住算术运算?,python,Python,我想知道是否存在允许我执行以下操作的python模块: x = MagicNumber() x.value = 3 y = 2 * (x + 2) ** 2 - 8 print y # 42 x.value = 2 print y # 24 因此,MagicNumber将实现所有特殊的操作符方法,它们将返回MagicNumber的实例,同时跟踪执行的操作。有这样的课吗 编辑:澄清 我想在一个模块中使用它,该模块应该记住用户希望执行的一些任意计算的许多参数。因此,用户将设置参数,然后使用

我想知道是否存在允许我执行以下操作的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代码,同时根据需要计算变量,以便在上下文中进行计算。一段时间后,您会注意到两个问题:

  • 变量和参数的数量使局部变量变得混乱,而且变量名很难记住。你应该把它们分成不同的类别,以便跟踪它们
  • 有时,您需要重新进行相同的计算,该计算在最后几章和十几行中进行,其中一个或多个参数发生了更改。您应该找到一些避免代码重复的方法
  • 这个问题引出了最初的问题。

    你可以尝试一下,一个用Python编写的计算机代数系统

    例如


    这不是叫
    函数吗?这听起来可能是一个简单的答案,但我是真心的

    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
    
    我建议看一个不同的符号(如),它可能有助于消除优先问题…

    类似的东西

    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)]
    

    我事先不知道将执行哪些算术运算,而且我可能不会假设它们是一次性完成的,或者是在同一个地方完成的。也许用一些预期的用例更新您的问题是个好主意。您将如何准确地构造这些操作,以及为什么不想将字符(例如,
    *
    )映射到函数(例如,
    乘法
    )?Re:update。你又把我关在一个特别的问题上。我不知道我的模块的用户希望做什么样的参数或问题。他应该可以自由地自己命名参数,并在他认为合适的时候使用它们,并且可以像计算正常值一样使用它们。我只是想给他额外的追溯性修改的能力。等等,最终用户会输入你在问题的第一个代码块中输入的代码吗?在这种情况下,您可以在
    eval
    命令中结束调用,在执行时替换变量:例如
    eval('2*(x+2)**2-8'.replace('x',str(3))
    --
    3
    x
    参数的当前值?好的,欢迎背景。从我对你的问题的设想来看,我仍然支持这个解决方案;可能是因为我不认为创建一个包含一些定义在其中的变量的类,以及一个可以清晰地注释和描述的计算函数有什么问题。我将保留我的答案,并建议您选择最符合您个人偏好的解决方案(我认为这可以归结为)。不要轻描淡写您的答案,而是出于好奇:与使用函数相比,这种构造有什么好处?我看起来不太清晰,你仍然需要用代码来构建它。。。在这种情况下,我真的对库的附加值很感兴趣。@jro:OP实际上要求提供一个代数库,这是一个(除其他外)处理代数的库。在函数上,这将允许求解或表达多个符号的方程,其中替换值包括符号。这与我的想法最接近,因为我可以通过几个步骤构建表达式。但是,使用此方法时,我需要调用一个特殊函数对其进行求值——我希望它是无缝的,并且从一开始就给
    x
    一个值。但也许我可以将
    Symbol
    子类化,这样做的工作量就会少很多。谢谢@eumiro,他事先不知道将执行哪些算术运算。我认为Python解释器将处理优先级问题-他不想解析表达式,他想将解析后的表达式捕获为可计算的(这是一个单词吗?)对象。有这样的类吗?保罗:“现在有了!”。我希望我有更多的选票。我站在一个巨人的肩膀上,呃,巨蟒?(蟒蛇有肩膀吗?)!对于符号代数,它还有一些缺点,但这不是批评。您必须注意分配给
    x.value
    :使用整数会得到意外的结果。还有一些符号操作也不错:在上面的例子中,
    -y
    是什么@保尔·麦奎尔:我会把这当作一个练习,因为我最近在一个类似的方向上进行实验,但我没有得出任何像你一样简洁的结论。如果用整数“你得到了意想不到的结果”,也许你指的是整数除法带来的惊喜。如果您想强制所有expr
    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)]