#python #numpy #numpy-ndarray
#python #numpy #numpy-ndarray
Вопрос:
Для проекта на python у меня есть задачи объединить работу двух коллег и вызвать их функции. Чтобы разобраться в сути проблемы, рассмотрим следующий сценарий:
Коллега А вычисляет значения положения и скорости объектов в своем модуле «body_class.py » это выглядит примерно так:
class Body:
def __init__(self, x, y, z, vx, vy, vz):
self.x = x
self.y = y
self.z = z
self.vx = vx
self.vy = vy
self.vz = vz
Для других функций, которые он запрограммировал, он хотел бы сохранить код как можно более чистым и называть компоненты векторов положения и скорости их соответствующими именами. По этой причине он сохранил их как отдельные переменные.
Коллеге B необходимо использовать значения положения и скорости всех объектов Body для некоторых вычислений, которые критичны по времени, поэтому он решил использовать numpy ndarrays для ускорения матричных вычислений. Входные данные, которые он ожидает для своей работы, — это 2D numpy ndarray, который содержит все компоненты положения и скорости всех объектов тела в форме (пример для трех объектов тела):
state = np.array([[2, 0, 3, -2, 0, -3], #Body 1
[0, 0, 1, 1, 0, 0], #Body 2
[0, 5, 2, 4, 3, 2]]) #Body 3
Есть ли способ объединить ясность кода при использовании объектно-ориентированных переменных экземпляра для операций коллеги A с преимуществами эффективности numpy для вычислений коллеги B?
Моя первоначальная идея состояла в том, чтобы сохранить ndarray, содержащий информацию о местоположении и скорости для всех объектов, в качестве переменной класса тела класса (чтобы коллега B мог легко получить доступ к этой переменной «состояние»), аналогично этому:
class Body:
states = np.empty([0,6])
def __init__(self, x, y, z, vx, vy, vz):
self.x = x
self.y = y
self.z = z
self.vx = vx
self.vy = vy
self.vz = vz
Body.states = np.concatenate((self.states, np.array([[self.x, self.y, self.z, self.vx, self.vy, self.vz]])), axis=0)
…и затем создать переменную экземпляра для каждого объекта Body, которая содержит только указатель / ссылку на соответствующий элемент ndarray (чтобы коллега A мог получить доступ к переменным, например, вызывая self.x изнутри класса без необходимости постоянно обновлять как эту переменную экземпляра, так и соответствующий элемент ndarray), ноЯ не знаю, возможно ли это реализовать в Python, не говоря уже о том, было бы ли это хорошим решением для этой ситуации или лучшим решением было бы просто использовать одну из обеих возможностей (ndarray VS переменные экземпляра)
Приветствуются любые идеи и советы! Заранее спасибо за вашу помощь!
Обновить:
Проект представляет собой симуляцию, поэтому два описанных выше действия выполняются на каждом временном шаге симуляции, что создает проблему с производительностью. Итак, я ищу решение, которое позволяет сохранять значения положения и скорости всех объектов Body непосредственно в одном большом 2D-массиве (который является необходимым вводом для коллеги B), в то же время позволяя получать к ним доступ по имени экземпляра объекта (например, b1.x) или другому болеезначимое имя вместо необходимости использовать индексы массива, такие как состояние [3,2] .
То, что я хотел бы предотвратить, — это сначала установить значения положения и скорости для каждого экземпляра тела в их атрибутах экземпляра, а затем снова создавать большой 2D-массив «state» на каждом временном шаге, перебирая все экземпляры тела и складывая их отдельные значения положения и скорости вместе (как дляя понимаю, что это было бы весьма пагубно для производительности, но, пожалуйста, поправьте меня, если я ошибаюсь)
Комментарии:
1. реализует ли Body что-нибудь еще, кроме хранения значений?
2. Да, тело имеет много других атрибутов, а также другие функции
3. Лучшая идея, которую я видел, — использовать
numpy
массивы в качестве основного хранилища и предоставить классам методы и индексы для доступа к их собственным значениям в массивах. Но, как правило,numpy
это плохо сочетается с обширной перспективой ООП. За исключением, конечно, того, чтоnumpy.ndarray
это высокоразвитый класс сам по себе.
Ответ №1:
Звучит как задание для именованного кортежа:
from collections import namedtuple
Body = namedtuple('Body', ['x', 'y', 'z', 'vx', 'vy', 'vz'])
b1 = Body(2,0,3,-2,0,3)
# now it is possible to access attributes both by name...
b1.x # returns 2
# ... and as an array
np.array(b1) # array([ 2, 0, 3, -2, 0, 3])
UPD: создание подклассов и отслеживание экземпляров объектов PoC
_Body = namedtuple('Body', ['x', 'y', 'z', 'vx', 'vy', 'vz'])
class Body(_Body):
instances = set()
def __new__(cls, *args, **kwargs):
body = super(Body, cls).__new__(cls, *args, **kwargs)
Body.instances.add(body)
return body
def __del__(self):
Body.instances.remove(self)
def xy(self):
return self.x self.y
@classmethod
def states(cls):
# will return a 2D numpy array of all Body instances
return np.array(list(cls.instances))
Комментарии:
1. Спасибо за ваш ответ! Я рассмотрю namedtuples. Я не знал о них. Для построения «состояний» ndarray, которые содержат все значения всех тел, мне пришлось бы перебирать все объекты Body с такой возможностью после их создания, верно? Или есть возможность сделать это быстрее?
2.
namedtuples
не помогает сnumpy
интерфейсом.3. @hpaulj они не устранят проблему полностью, но они определенно упростят задачу
4. @diamon можно создать подкласс из namedtuple для реализации и других методов. Однако я не уверен, что вы подразумеваете под циклом по всему телу — нужно ли отслеживать все созданные объекты этого типа?
5. У меня сложилось впечатление, что OP хочет массив (или массивы), которые содержат значения для многих из этих объектов. Некоторые пытаются создавать массивы объектов типа object dtype, но результат не лучше (а может и хуже), чем список объектов.