python - 同情如何运作?它如何与交互式 Python shell 交互,交互式 Python shell 是如何工作的?

标签 python scripting eval interactive sympy

当我按下 Enter 时内部会发生什么?

除了单纯的好奇之外,我问的动机是想弄清楚当你这样做时会发生什么

from sympy import *

然后输入一个表达式。从Enter到调用

是怎样的
__sympifyit_wrapper(a,b)

在 sympy.core.decorators 中? (当我尝试检查评估时,这是第一个 winpdb 带我去的地方。)我猜想有一些内置的 eval 函数可以正常调用,并且在您导入 sympy 时被覆盖?

最佳答案

好吧,在玩了一会儿之后我想我明白了..当我第一次问这个问题时我不知道 operator overloading .

那么,这个 python session 中发生了什么?

>>> from sympy import *
>>> x = Symbol(x)
>>> x + x
2*x

事实证明,解释器如何计算表达式并没有什么特别之处;重要的是python翻译

x + x

进入

x.__add__(x)

而Symbol继承自Basic类,定义了__add__(self, other)返回Add(self, other)。 (如果您想看一下,可以在 sympy.core.symbol、sympy.core.basic 和 sympy.core.add 中找到这些类。)

正如 Jerub 所说,Symbol.__add__() 有一个 decorator称为 _sympifyit ,它在评估函数之前基本上将函数的第二个参数转换为 sympy 表达式,在此过程中返回一个名为 __sympifyit_wrapper 的函数,这是我之前看到的。

使用对象来定义操作是一个非常巧妙的概念;通过定义您自己的运算符和字符串表示,您可以很容易地实现一个简单的符号代数系统:

符号.py --

class Symbol(object):
    def __init__(self, name):
        self.name = name
    def __add__(self, other):
        return Add(self, other)
    def __repr__(self):
        return self.name

class Add(object):
    def __init__(self, left, right):
        self.left = left
        self.right = right
    def __repr__(self):
        return self.left + '+' + self.right

现在我们可以做:

>>> from symbolic import *
>>> x = Symbol('x')
>>> x+x
x+x

通过一些重构,它可以轻松扩展以处理所有 basic arithmetic :

class Basic(object):
    def __add__(self, other):
        return Add(self, other)
    def __radd__(self, other): # if other hasn't implemented __add__() for Symbols
        return Add(other, self)
    def __mul__(self, other):
        return Mul(self, other)
    def __rmul__(self, other):
        return Mul(other, self)
    # ...

class Symbol(Basic):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name

class Operator(Basic):
    def __init__(self, symbol, left, right):
        self.symbol = symbol
        self.left = left
        self.right = right
    def __repr__(self):
        return '{0}{1}{2}'.format(self.left, self.symbol, self.right)

class Add(Operator):
    def __init__(self, left, right):
        self.left = left
        self.right = right
        Operator.__init__(self, '+', left, right)

class Mul(Operator):
    def __init__(self, left, right):
        self.left = left
        self.right = right
        Operator.__init__(self, '*', left, right)

# ...

只需稍微调整一下,我们就可以从一开始就获得与 sympy session 相同的行为。我们将修改 Add 以便它返回一个 Mul 实例,如果它的参数是相等的。这有点棘手,因为我们在实例创建之前已经完成了;我们必须使用 __new__() instead of __init__() :

class Add(Operator):
    def __new__(cls, left, right):
        if left == right:
            return Mul(2, left)
        return Operator.__new__(cls)
    ...

不要忘记为 Symbols 实现相等运算符:

class Symbol(Basic):
    ...
    def __eq__(self, other):
        if type(self) == type(other):
            return repr(self) == repr(other)
        else:
            return False
    ...

瞧。无论如何,您可以想到要实现的各种其他东西,例如运算符优先级、替换求值、高级简化、微分等,但我认为基础如此简单非常酷。

关于python - 同情如何运作?它如何与交互式 Python shell 交互,交互式 Python shell 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3191749/

相关文章:

python - 为什么我在安装时不断收到此消息说 EntryPoint must be in 'name=module :attrs [extras]

shell - Unix 变量声明

c# - 将对象公开给 VBScript 时出现 MSScriptControl 'Specified cast is not valid'

selenium - 使用 Selenium IDE 的 CSP 阻止调用 eval()

javascript - 在 Javascript 中创建一个可以访问局部变量的类

python - 将整数转换为其 ascii 值的字符串

python - 如何将 Python dict 转换为特定类型的对象?

python - 使用 Pandas 标记每组的第 N 行

python - paraview python shell 中的输入语法

javascript - 代码执行的时间限制