2015-06-26 3 views
6

Мне недавно пришлось выполнить задание, в котором использовалось множество операций с координатами. Думая, чтобы сэкономить время и упростить мой код, я определил класс для инкапсуляции поведения пары координат. Класс выглядел следующим образом:Чрезвычайно медленный экземпляр объекта в Python 2.7

class Vector (tuple) : 
    def __init__ (self, value) : 
     tuple.__init__ (self, value) 


    def __add__ (self, other) : 
     return Vector ((self [0] + other [0], self [1] + other [1])) 

Это позволило мне писать код, как это (для примера):

def translate (pointList, displacement) : 
    return [point + displacement for point in pointList] 

Но мое приложение было ужасно медленно. Гораздо медленнее, чем другие задания. Я не мог найти какую-либо неэффективность в моей реализации алгоритма, поэтому я сделал простой тест, чтобы узнать, что накладные расходы класса Vector. Я ожидал где-то от 5% до 15%.

Мой тест векторного класса выглядит следующим образом:

v = Vector ((0, 0)) 
d = Vector ((1, -1)) 
loopIdx = 3000000 
while loopIdx > 0 : 
    v = v + d 
    loopIdx -= 1 
print (v) 

Это работает (как правило) в этом виде времени:

real 0m8.440s 
user 0m8.367s 
sys  0m0.016s 

Для сравнения я побежал этот код:

v = (0, 0) 
dX = 1 
dY = -1 
loopIdx = 3000000 
while loopIdx > 0 : 
    v = (v [0] + dX, v [1] + dY) 
    loopIdx -= 1 
print (v) 

Время выполнения для этого кода:

real 0m1.004s 
user 0m0.995s 
sys  0m0.006s 

Я сделал что-то серьезно неправильно, или использование объектов класса в Python действительно означает, что ваше приложение займет более 8 раз?

+0

Это, скорее всего, не сам класс, более тот кортеж реализован непосредственно на C, а ваш класс - нет. –

+1

Не ответ на вопрос, но: Вместо вашего класса «Вектор» вы можете просто использовать «сложные» цифры для представления 2D-координат. Дополнение, субстрат, абсолютная величина (для расстояния) и т. Д. Включены.Кроме того, это еще в 2-3 раза быстрее, чем использование кортежей, как в вашем втором подходе. –

+1

Вы можете рассмотреть класс с '__slots__', чтобы свести к минимуму объем памяти каждого экземпляра. – jonrsharpe

ответ

1

Не совсем ответ, как сделать вас классом быстрее, но больше альтернативы.

Вместо подклассов tuple и писать все те add, sub и т.д. методы себя, вы просто использовать холодный bultin complex тип номера Python для 2D координат, которая все эти операции уже встроены, правильно и и очень быстро.

>>> %timeit vector_no_init() 
1 loops, best of 3: 1.39 s per loop 
>>> %timeit plain_tuple() 
1 loops, best of 3: 403 ms per loop 
>>> %timeit complex_nums() 
1 loops, best of 3: 171 ms per loop 

Для вращения, вы можете использовать комплексное умножение: Просто умножьте ваш комплекс координируют с комплексным числом, которое имеет, в полярной форме, абсолютное значение 1 и фазы, равный углу вы хотите повернуть на. Чтобы повернуть на 90 градусов, вы можете просто умножить на 1j (против часовой стрелки) или -1j (по часовой стрелке). Для всех других углов используйте модуль cmath для перевода в полярную форму и из нее.

>>> c = complex(4, 2) 
>>> c * cmath.rect(1, math.radians(45)) 
(1.4142135623730954+4.242640687119285j) 

Однако, я хотел бы предложить не подкласс complex сделать rotate метод этого класса, так как в этом случае вам придется переписать все другие методы, такие как add, а также, в противном случае результат добавления будет регулярным комплексным числом, не предоставляющим метод rotate. И это отменит все эти достижения в производительности, сделав их такими же медленными, как ваш класс Vector. Вместо этого просто сделайте функцию rotate(complex, angle) -> complex.

+0

Спасибо. В качестве предварительного результата использование 'complex' для замены исходной арифметики' tuple' (без класса) позволяет повысить производительность на 40%. –