numpy对象数组

2024-04-29 20:03:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在Python中实现一个格子模型(格子boltzmann)的模拟。格点的每个位置都有许多性质,并根据一定的规则与相邻位置相互作用。我认为创建一个包含所有属性的类并为该类的实例创建一个网格可能是明智的。(由于我对Python缺乏经验,这可能根本不是一个好主意,所以请随意评论我的方法。)

这是我正在做的一个玩具例子

class site:
    def __init__(self,a,...):
        self.a = a
        .... other properties ...
    def set_a(self, new_a):
        self.a = new_a

现在我想处理这样的站点的二维/三维网格(grid),所以我尝试执行以下操作(这里是一个2d3x3网格作为示例,但在模拟中,我需要的顺序是>;10000x1000x1000)

lattice = np.empty( (3,3), dtype=object)
lattice[:,:] = site(3)

现在,问题是每个晶格点都引用同一个实例,例如

lattice[0,0].set_a(5)

也会将晶格[0,2].a的值设置为5。这种行为是不必要的。为了避免这个问题,我可以在每个网格点上循环并按元素分配对象,比如

for i in range(3):
    for j in range(3):
        lattice[i,j] = site(a)

但是有没有更好的方法(不包括循环)将对象分配给多维数组呢?

谢谢


Tags: 对象实例方法in模型self网格new
3条回答

我不知道更好,但是作为一个显式循环集的替代,您可以编写

lattice = np.empty( (3,3), dtype=object)
lattice.flat = [site(3) for _ in lattice.flat]

无论晶格的形状如何都能起作用。

您可以vectorize类的__init__函数:

import numpy as np

class Site:
    def __init__(self, a):
        self.a = a
    def set_a(self, new_a):
        self.a = new_a

vSite = np.vectorize(Site)

init_arry = np.arange(9).reshape((3,3))

lattice = np.empty((3,3), dtype=object)
lattice[:,:] = vSite(init_arry)

这看起来更干净,但与循环解决方案相比没有性能优势。列表理解答案创建一个中间python列表,这将导致性能下降。

对您来说,缺少的一点是Python将所有内容都视为引用。(有一些“不可变”的对象、字符串、数字和元组,它们更像是值。)

lattice[:,:] = site(3)

你说的是“Python:make a new objectsite,并告诉lattice中的每个元素指向该对象。”要查看实际情况,请打印数组以查看对象的内存地址是否都相同:

array([[<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>],
       [<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>],
       [<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>]], dtype=object)

循环方法是一种正确的方法。对于numpy数组,这可能是您的最佳选择;对于Python列表,您还可以使用列表理解:

lattice = [ [Site(i + j) for i in range(3)] for j in range(3) ]

可以将列表理解与numpy.array结构一起使用:

lattice = np.array( [ [Site(i + j) for i in range(3)] for j in range(3) ],
                    dtype=object)

现在,当您打印lattice

array([[<__main__.Site object at 0x1029d53d0>,
        <__main__.Site object at 0x1029d50d0>,
        <__main__.Site object at 0x1029d5390>],
       [<__main__.Site object at 0x1029d5750>,
        <__main__.Site object at 0x1029d57d0>,
        <__main__.Site object at 0x1029d5990>],
       [<__main__.Site object at 0x1029d59d0>,
        <__main__.Site object at 0x1029d5a10>,
        <__main__.Site object at 0x1029d5a50>]], dtype=object)

所以你可以看到里面的每一个物体都是独一无二的。

您还应该注意,“setter”和“getter”方法(例如,set_a)不是Pythonic方法。最好直接设置和获取属性,如果确实需要防止对属性的写访问,则使用@property装饰器。

还要注意,Python类的标准是使用CamelCase编写,而不是小写。

相关问题 更多 >