当我按下 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/