Как соотносятся полиморфизм и байт-код в питоне?
Как работает полиморфизм под капотом в питоне?
В Python, если у меня есть какая-то функция, например
def f(x):
return x + 2*x + 3*x + 4*x + 5*x + 6*x
затем в соответствии с dis.dis(f)
Python переводит это в инструкции байт-кода, которые описывают цикл:
- загрузка следующего постоянного значения
- погрузка
x
снова - умножая их вместе
- добавление товара (на накопление предыдущих сроков)
Но если x
это numpy
вместо массива или класса Python, а не базового типа данных, предположительно, интерпретатор должен выполнять дополнительную работу (например, двоичный код операции умножения должен каким-то образом приводить к вызову других функций, возможно, начиная с поиска некоторых атрибутов, которые обычно соответствуют совершенно другим оП-кода). Это кажется очень отличным от обычного языка ассемблера, где простая арифметическая операция была бы атомарной (и не заставляла бы ЦП также выполнять дополнительные инструкции, которые не видны в листинге разборки).
Есть ли документация о том, как работает интерпретатор python, и какую последовательность шагов он фактически выполняет при оценке выражения, включающего полиморфизм? (В идеале, на более низком уровне детализации, чем может показывать пошаговый отладчик Python?)
Редактировать:
Для поддержки полиморфизма арифметическая операция должна также включать не только арифметику, но и проверку типов, поиск атрибутов, условные переходы и вызовы функций. (Все эти вещи имеют свои собственные коды операций.) Правильно ли, что cpython реализует это, заставляя арифметический код операции сам выполнять множество сложных действий за один шаг интерпретатора (за исключением инструкций, содержащихся в вызываемой функции), вместо того, чтобы показывать интерпретатору последовательность отдельных кодов операций для достижения того же результата (например, LOAD_ATTR, CALL_FUNCTION и т. д.)?
Есть ли какая-либо документация, такая как таблица, для всех кодов операций, описывающая все действия, которые может вызывать каждый код операции?
1 ответ
Вы можете определить поведение оператора для пользовательского класса, реализовав соответствующий магический метод:
>>> class MyClass(object):
... def __add__(self, x):
... return '%s plus %s' % (self, x)
... def __mul__(self, x):
... return "%s mul %s" % (self, x)
И я думаю, вот как array
в numpy
делает работу под капотом.
Вы можете проследить это для получения дополнительной информации о реализации *
для NumPy array