Python numpy 对象数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4877624/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
numpy array of objects
提问by jonalm
I'm trying to implement a simulation for a lattice model (lattice boltzmann) in Python. Each site of the lattice has a number of properties, and interact with neighboring sites according to certain rules. I figured that it might be clever to make a class with all the properties and make a grid of instances of that class. (As I'm inexperienced with Python, this might not be a good idea at all, so feel free to comment on my approach.)
我正在尝试在 Python 中实现对晶格模型(lattice boltzmann)的模拟。格子的每个站点都有许多属性,并根据一定的规则与相邻站点相互作用。我认为创建一个具有所有属性的类并创建该类实例的网格可能很聪明。(由于我对 Python 缺乏经验,这可能根本不是一个好主意,所以请随时对我的方法发表评论。)
Here is a toy example of what I'm doing
这是我正在做的事情的一个玩具示例
class site:
def __init__(self,a,...):
self.a = a
.... other properties ...
def set_a(self, new_a):
self.a = new_a
Now I want to deal with a 2D/3D lattice (grid) of such sites so I tried to do the following (here is a 2D 3x3 grid as an example, but in simulation I would need the order of >1000x1000X1000)
现在我想处理此类站点的 2D/3D 点阵(网格),因此我尝试执行以下操作(这里以 2D 3x3 网格为例,但在模拟中我需要 >1000x1000X1000 的顺序)
lattice = np.empty( (3,3), dtype=object)
lattice[:,:] = site(3)
Now, the problem is that each lattice point refer to the same instance, for example
现在,问题是每个格点都指向同一个实例,例如
lattice[0,0].set_a(5)
will also set the value of lattice[0,2].a to 5. This behavior is unwanted. To avoid the problem i can loop over each grid point and assign the objects element by element, like
还将把lattice[0,2].a 的值设置为5。这种行为是不需要的。为了避免这个问题,我可以遍历每个网格点并逐个元素分配对象,例如
for i in range(3):
for j in range(3):
lattice[i,j] = site(a)
But is there a better way (not involving the loops) to assign objects to a multidimensional array?
但是有没有更好的方法(不涉及循环)将对象分配给多维数组?
Thanks
谢谢
采纳答案by Paul
You can vectorizethe class's __init__function:
您可以对类的函数进行矢量化__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)
This may look cleaner but has no performance advantage over your looping solution. The list comprehension answers create an intermediate python list which would cause a performance hit.
这可能看起来更干净,但与循环解决方案相比没有性能优势。列表理解答案会创建一个中间的 Python 列表,这会导致性能下降。
回答by Seth Johnson
The missing piece for you is that Python treats everything as a reference. (There are some "immutable" objects, strings and numbers and tuples, that are treated more like values.) When you do
您缺少的部分是 Python 将所有内容都视为参考。(有一些“不可变”对象、字符串、数字和元组,它们更像是值。)
lattice[:,:] = site(3)
you are saying "Python: make a new object site, and tell every element of latticeto point to that object." To see that this is really the case, print the array to see that the memory addresses of the objects are all the same:
你在说“Python:创建一个新对象site,并告诉每个元素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)
The loop way is one correct way to do it. With numpy arrays, that may be your best option; with Python lists, you could also use a list comprehension:
循环方式是一种正确的方法。使用 numpy 数组,这可能是您的最佳选择;对于 Python 列表,您还可以使用列表理解:
lattice = [ [Site(i + j) for i in range(3)] for j in range(3) ]
You can use a list comprehension with the numpy.arrayconstruction:
您可以在numpy.array构造中使用列表理解:
lattice = np.array( [ [Site(i + j) for i in range(3)] for j in range(3) ],
dtype=object)
Now when you print lattice, it's
现在当你打印时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)
so you can see that every object in there is unique.
所以你可以看到里面的每个对象都是独一无二的。
You should also note that "setter" and "getter" methods (e.g., set_a) are un-Pythonic. It's better to set and get attributes directly, and then use the @propertydecorator if you REALLY need to prevent write access to an attribute.
您还应该注意“setter”和“getter”方法(例如,set_a)是非 Pythonic 的。最好直接设置和获取属性,然后@property如果您真的需要防止对属性进行写访问,则使用装饰器。
Also note that it's standard for Python classes to be written using CamelCase, not lowercase.
另请注意,使用 CamelCase 而不是小写字母编写 Python 类是标准的。
回答by DSM
I don't know about better, but as an alternative to an explicit set of loops, you could write
我不知道更好,但作为一组显式循环的替代,你可以写
lattice = np.empty( (3,3), dtype=object)
lattice.flat = [site(3) for _ in lattice.flat]
which should work whatever the shape of the lattice.
无论晶格的形状如何,它都应该起作用。

