You can vectorize the class's __init__ function:
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.
Answer from Paul on Stack OverflowYou can vectorize the class's __init__ function:
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.
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
lattice[:,:] = site(3)
you are saying "Python: make a new object site, and tell every element of lattice to 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:
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:
lattice = [ [Site(i + j) for i in range(3)] for j in range(3) ]
You can use a list comprehension with the numpy.array construction:
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
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 @property decorator if you REALLY need to prevent write access to an attribute.
Also note that it's standard for Python classes to be written using CamelCase, not lowercase.