【问题标题】:python: iterate using a class methodpython:使用类方法进行迭代
【发布时间】:2011-03-28 14:42:50
【问题描述】:

我仍在研究 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 中的一个复杂值做到这一点, 不必传递一个只有一个值的列表?还是我必须做一些测试?

【问题讨论】:

  • 等等!您似乎正在尝试遍历裂纹对象列表而不是单个裂纹。在我看来,crack_list 不包含列表对象,而是包含单个列表对象。可以验证吗?

标签: python numpy matplotlib


【解决方案1】:

要可迭代的对象需要有__iter__() 方法,该方法返回一个迭代器(或序列)。迭代器应该实现方法next(),这将产生元素或raise StopIteration 是没有更多的元素。就这么简单。

【讨论】:

  • 如果__iter__ 返回的不是迭代器,例如非迭代器序列,iter() 将引发 TypeError。
【解决方案2】:

除了get_pot() 方法不返回任何内容之外,您似乎没有在任何地方定义self.nself.coeffs。我打赌 coeffs 是一个 numpy 向量,n 它的长度,我假设它们可以在 Crack 对象之间变化,就像 z1z2

基于这些假设,我稍微调整了您的课程:

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))
                )

现在,假设您拥有(或可以生成)每个 Crackz1z2coeffs 值的列表:

>>> # 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

您可以像这样使用内置函数map() 制作crack_list

>>> 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.0z = 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

瞧。作为检查,我还会做一些纸笔计算,以确保大方程式正在做它应该做的事情。

【讨论】:

    【解决方案3】:

    您可以使用列表推导式创建潜力列表,替换

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

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

    Map 和 reduce 也可以在这种情况下使用。

    【讨论】:

      【解决方案4】:

      首先,我没有看到您的 get_pot 方法返回任何内容。我想它应该以return result 结尾。

      第二个权宜之计是遍历您的对象列表:

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

      但理想情况下,由于您使用的是 numpy,您应该让您的类接受数组(看起来可能已经)。看看当您输入sz1sz2z 作为等形状的二维数组时会发生什么。如果只对一个轴求和,get_pot 应该返回一个可迭代数组。这将避免创建实例列表并利用 numpy 提供的加速。 (这个解决方案的有效性有点取决于你拥有的破解实例的数量以及你创建和销毁新实例的频率)

      【讨论】:

        猜你喜欢
        • 2016-08-27
        • 2022-12-14
        • 2015-03-10
        • 1970-01-01
        • 2011-01-20
        • 1970-01-01
        • 1970-01-01
        • 2022-10-04
        • 1970-01-01
        相关资源
        最近更新 更多