Как sympy работает? Как это взаимодействует с интерактивной оболочкой Python, и как интерактивный Python окружает работу?

Что происходит внутренне, когда я нажимаю Enter?

Моя мотивация для выяснения, помимо простого любопытства, должна выяснить то, что происходит когда Вы

from sympy import *

и введите выражение. Как это идет от, Входят до вызова

__sympifyit_wrapper(a,b)

в sympy.core.decorators? (Это - первое место winpdb, взял меня, когда я пытался осмотреть оценку.) Я предположил бы, что существует некоторая встроенная функция оценки, которая вызывается обычно и переопределяется, когда Вы импортируете sympy?

16
задан Omnifarious 18 August 2010 в 05:30
поделиться

4 ответа

Хорошо, поиграв с этим еще немного, я думаю, что понял... когда я впервые задал вопрос, я не знал о перегрузке операторов.

Итак, что происходит в этой сессии python?

>>> 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, если вы хотите взглянуть)

Итак, как говорил Джеруб, Symbol. __add__() имеет декоратор под названием _sympifyit, который в основном преобразует второй аргумент функции в выражение sympy перед оценкой функции, в процессе чего возвращает функцию под названием __sympifyit_wrapper, что я и видел ранее.

Использование объектов для определения операций - довольно хитрая концепция; определив собственные операторы и представления строк, можно довольно легко реализовать тривиальную систему символьной алгебры:

symbolic. 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

С помощью небольшого рефакторинга ее можно легко расширить для обработки всех основных арифметических операций:

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 с самого начала... Мы изменим Add так, чтобы он возвращал экземпляр Mul, если его аргументы равны. Это немного сложнее, поскольку мы должны добраться до него до создания экземпляра; мы должны использовать __new__() вместо __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
    ...

И вуаля. В любом случае, вы можете придумать множество других вещей для реализации, таких как старшинство операторов, оценка с подстановкой, расширенное упрощение, дифференцирование и т.д., но я думаю, что это очень здорово, что основы так просты.

11
ответ дан 30 November 2019 в 21:53
поделиться

Я только что проверил код sympy (на http://github.com/sympy/sympy ), и он выглядит например __ sympifyit_wrapper - декоратор. Причина, по которой он будет вызван, заключается в том, что где-то есть код, который выглядит примерно так:

class Foo(object):
    @_sympifyit
    def func(self):
        pass

И __ sympifyit_wrapper - это оболочка, возвращаемая @_ sympifyit . Если вы продолжили отладку, возможно, вы нашли функцию (в моем примере с именем func ).

Я собрал в одном из многих модулей и пакетов, импортированных в sympy / __ init __. Py , часть встроенного кода заменена версиями sympy. Эти версии sympy, вероятно, используют этот декоратор.

exec , используемый >>> , не будет заменен, объекты, над которыми работают, будут заменены.

5
ответ дан 30 November 2019 в 21:53
поделиться

Это не имеет ничего общего с реальным вопросом secondbanana - это просто выстрел в награду Omnifarious;)

Сам интерпретатор довольно прост. Фактически, вы можете написать простой запрос (не идеальный, не обрабатывает исключения и т. Д.) Самостоятельно:

print "Wayne's Python Prompt"

def getline(prompt):
    return raw_input(prompt).rstrip()

myinput = ''

while myinput.lower() not in ('exit()', 'q', 'quit'):
    myinput = getline('>>> ')
    if myinput:
        while myinput[-1] in (':', '\\', ','):
            myinput += '\n' + getline('... ')
        exec(myinput)

Вы можете делать большую часть того, к чему вы привыкли, в обычном приглашении:

Waynes Python Prompt
>>> print 'hi'
hi
>>> def foo():
...     print 3
>>> foo()
3
>>> from dis import dis
>>> dis(foo)
  2           0 LOAD_CONST               1 (3)
              3 PRINT_ITEM
              4 PRINT_NEWLINE
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE
>>> quit
Hit any key to close this window...

Настоящая магия происходит в лексере / парсере.

Lexical Analysis, или lexing , разбивает ввод на отдельные токены. Токены - это ключевые слова или «неделимые» элементы. Например, = , если , попробуйте , : , для , пройти , и import - все токены Python.Чтобы увидеть, как Python токенизует программу, вы можете использовать модуль tokenize .

Поместите код в файл с именем 'test.py' и запустите в этом каталоге следующее:

from tokenize import tokenize f = open ('test.py') tokenize (f.readline)

Для print «Hello World!» вы получите следующее:

1,0-1,5: NAME 'print'
1,6–1,19: STRING '"hello world"'
1,19–1,20: NEWLINE '\ n'
2,0-2,0: ENDMARKER ''

После токенизации кода он анализирует в абстрактное синтаксическое дерево . Конечным результатом является представление вашей программы в виде байт-кода на языке Python. Для выведите «Hello World!» вы можете увидеть результат этого процесса:

from dis import dis
def heyworld():
    print "Hello World!"
dis(heyworld)

Конечно, все языки лексируют, анализируют, компилируют и затем выполняют свои программы. Лексы Python, синтаксический анализ и компиляция в байт-код. Затем байт-код «компилируется» (может быть более точным переводом) в машинный код, который затем выполняется. Это основное различие между интерпретируемыми и скомпилированными языками - скомпилированные языки компилируются непосредственно в машинный код из исходного источника, что означает, что вам нужно только lex / parse перед компиляцией, а затем вы можете напрямую выполнить программу. Это означает более быстрое время выполнения (без этапа lex / parse), но это также означает, что для достижения этого начального времени выполнения вам придется потратить намного больше времени, потому что вся программа должна быть скомпилирована.

6
ответ дан 30 November 2019 в 21:53
поделиться

Интерактивный интерпретатор Python не делать многое, отличное от любого другого запуска кода Python. У него есть некоторая магия для перехвата исключений и обнаружения неполных многострочных операторов перед их выполнением, чтобы вы могли закончить их вводить, но это все.

Если вам действительно интересно, стандартный модуль кода представляет собой довольно полную реализацию интерактивной подсказки Python. Я думаю, что это не совсем то, что на самом деле использует Python (то есть, я считаю, реализованный на C), но вы можете покопаться в каталоге системной библиотеки Python и посмотреть, как это делается. Мой по адресу /usr/lib/python2.5/code.py

1
ответ дан 30 November 2019 в 21:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: