python: итерация с использованием метода класса - PullRequest
0 голосов
/ 28 марта 2011

Я все еще копаюсь в python, и есть кое-что, что мешает моему фону C ++. Например, у меня есть класс

class crack(object):

   def __init__(self, sz1,sz2):
        self.z1 = sz1
        self.z2 = sz2

   def smallz_Z(self,z,z1,z2):
       return z - 0.5*(z2-z1)

   def get_pot(self,z):
        Z = smallz_Z(z,self.z1,self.z2)

        try:
             result = np.sum(np.arange(self.n) * self.coeffs * (1.0 / (cmath.sqrt(Z - 1.0) * cmath.sqrt(Z + 1.0))) 
                        * ((Z - cmath.sqrt(Z - 1.0) * cmath.sqrt(Z + 1.0)) ** np.arange(self.n))) * (2.0 / (self.z2 - self.z1))

Я собираюсь создать список элементов трещины,

crack_list = []
crack_list.append(crack(z1,z2)) ...

И теперь мне нужно использовать итератор, чтобы получить все значения потенциала, например, для функции контура matplotlib. Я не могу делать такие вещи:

result = np.sum(crack_list.get_potential(z))

Прямо сейчас я делаю «традиционный» путь:

def potential_value(z, crack_list):
     potential = complex(0, 0)

     for element in crack_list:
     potential = potential + element.get_potential(z)

    return potential

и если я использую цикл for, он говорит, что трещина элемента не повторяется. Допустим, я пытаюсь

    x = np.linspace(self.x1, self.x2, self.step)
    y = np.linspace(self.y1, self.y2, self.step)
    X, Y = np.meshgrid(x, y)
    Z = X +1j*Y

    F = np.vectorize(potential_value)

но здесь у меня проблема:

   F(Z, crack_list)

   for element in crack_list:
      TypeError: 'crack' object is not iterable

Как я могу это сделать? Спасибо.

РЕДАКТИРОВАТЬ: Спасибо за ответы. Я все еще узнаю, что такое понимание списков, поэтому оно все еще бьет меня. Допустим, я хочу изменить свою реализацию для понимания списка, поэтому я изменил функцию на

def potential_value(z_list, crack_list, u_flow):

return [np.sum([c.get_potential(z) for c in crack_list]) + u_flow.get_potential_no_c(z) for z in z_list]

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

Ответы [ 4 ]

5 голосов
/ 28 марта 2011

Объект, который должен быть повторяем, должен иметь метод __iter__(), который возвращает итератор (или последовательность).Итератор должен реализовать метод next(), который будет выдавать элементы или raise StopIteration, если элементов больше нет.Так просто.

1 голос
/ 28 марта 2011

В дополнение к методу get_pot(), который ничего не возвращает, похоже, вы нигде не определяете self.n или self.coeffs.Я держу пари, что coeffs должен быть пустым вектором, а n его длиной, и я предполагаю, что они могут варьироваться между Crack объектами, как z1 и z2.

Исходя из этих предположений, я немного подправил ваш класс:

class Crack(object): # convention is to use capitalized class names

    def __init__(self, z1, z2, coeffs):
        self.z1 = z1
        self.z2 = z2
        self.coeffs = np.array(coeffs)
        self.n = len(coeffs)

    def __repr__(self):
        return "Crack(z1=%s, z2=%s, coeffs=%s)" % (self.z1, 
                                                   self.z2, 
                                                   self.coeffs)
    def get_big_Z(self, little_z):
        # this may not need to be its own function, unless you
        # use it separately from get_potential()
        return little_z - 0.5 * (self.z2 - self.z1)

    def get_potential(self, z):
        Z = self.get_big_Z(z)
        return (np.sum(np.arange(self.n) * self.coeffs * 
                       (1.0 / (np.sqrt(Z - 1.0) * np.sqrt(Z + 1.0))) * 
                       ((Z - np.sqrt(Z - 1.0) * np.sqrt(Z + 1.0)) ** 
                       np.arange(self.n))) * 
                (2.0 / (self.z2 - self.z1))
                )

Теперь предположим, что у вас есть (или вы можете сгенерировать) список значений z1, z2 и coeffs длякаждый Crack:

>>> # dummy information, this makes three Crack objects
...
>>> z1_values = [3.0, 1.1, 0.2]
>>> z2_values = [0.01, 0.02, 0.03]
>>> coeff_values = [[1.1,1.0],
...                 [2.2,2.0],
...                 [3.3,3.0]]

Списки coeff преобразуются в ndarray при создании объекта.

Вы можете сделать crack_list со встроенной функцией map() примерно так:

>>> crack_list = map(Crack, z1_values, z2_values, coeff_values)
>>> from pprint import pprint
>>> pprint(crack_list)
[Crack(z1=3.0, z2=0.01, coeffs=[ 1.1  1. ]),
 Crack(z1=1.1, z2=0.02, coeffs=[ 2.2  2. ]),
 Crack(z1=0.2, z2=0.03, coeffs=[ 3.3  3. ])]

Затем вы можете вычислить общий потенциал для некоторых z значений, скажем z = 5.0 или z = 3.14, например:

>>> def total_potential(z, cracks):
...     return sum(c.get_potential(z) for c in cracks)
...
>>>
>>> print total_potential(5.0, crack_list)
-0.772861759407
>>> print total_potential(3.14, crack_list)
-1.99073949493

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

1 голос
/ 28 марта 2011

Вы можете создать список потенциалов с пониманием списка, заменив

result = np.sum(crack_list.get_potential(z))

на

result = np.sum([elem.get_potential(z) for elem in crack_list])

Карта и уменьшение также могут использоваться в этом контексте.

1 голос
/ 28 марта 2011

Во-первых, я не вижу, чтобы ваш метод get_pot что-то возвращал. Это должно закончиться return result я думаю.

Во-вторых, мера стоп-пробел будет заключаться в итерации по вашему списку объектов:

[e.get_pot(i) for i in range(10)]

Но в идеале, поскольку вы используете numpy, вы должны заставить свой класс принимать массивы (что, похоже, уже могло бы). Посмотрите, что происходит, когда вы вводите sz1, sz2 и z в виде двумерных массивов одинаковой формы. Если вы суммируете только по одной оси, get_pot должен затем вернуть итеративный массив. Это позволит избежать создания списков экземпляров и воспользоваться преимуществами ускорений, которые предлагает numpy. (Эффективность этого решения немного зависит от количества имеющихся у вас экземпляров взлома и от того, как часто вы создаете и уничтожаете новые экземпляры)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...