我正在尝试用Python实现一个晶格模型(晶格boltzmann)的模拟。该网格的每个站点都具有多个属性,并根据一定的规则与相邻站点交互。我认为创建一个具有所有属性的类并创建该类的实例网格可能更聪明。(由于我没有使用Python的经验,这可能根本不是一个好主意,所以请随时对我的方法发表评论。)
这是我正在做的一个玩具示例
class site:
def __init__(self,a,...):
self.a = a
.... other properties ...
def set_a(self, new_a):
self.a = new_a
现在我想要处理这样的站点的2D/3D网格(网格),所以我尝试执行以下操作(这里是2D3x3网格作为示例,但在模拟中,我需要>1000x1000X1000的顺序)
lattice = np.empty( (3,3), dtype=object)
lattice[:,:] = site(3)
现在,问题是每个格点引用相同的实例,例如
lattice[0,0].set_a(5)
还会将lattice0,2.a的值设置为5。这是不需要的行为。为了避免这个问题,我可以遍历每个网格点并逐个元素地分配对象,如下所示
for i in range(3):
for j in range(3):
lattice[i,j] = site(a)
但是,有没有更好的方法(不涉及循环)将对象分配给多维数组?
谢谢
发布于 2011-02-03 02:18:21
您可以对类的__init__
函数执行vectorize:
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列表,这将导致性能下降。
发布于 2011-02-03 01:34:06
对于您来说,缺少的一部分是Python将所有内容都视为引用。(有一些“不可变”对象,字符串、数字和元组,它们更像是值。)当你这样做的时候
lattice[:,:] = site(3)
您说的是“lattice
:创建一个新对象site
,并告诉Python的每个元素指向该对象。”要查看实际情况,可以打印数组以查看对象的内存地址是否都相同:
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
装饰器。
还要注意的是,使用CamelCase而不是小写来编写Python类是标准的。
发布于 2011-02-03 02:22:53
我不知道是不是更好,但作为一组显式循环的替代方案,您可以这样写
lattice = np.empty( (3,3), dtype=object)
lattice.flat = [site(3) for _ in lattice.flat]
无论晶格的形状如何,它都应该起作用。
https://stackoverflow.com/questions/4877624
复制相似问题