массив объектов - PullRequest
       20

массив объектов

22 голосов
/ 02 февраля 2011

Я пытаюсь реализовать симуляцию для решеточной модели (решетки Больцмана) в Python.Каждый узел решетки обладает рядом свойств и взаимодействует с соседними узлами согласно определенным правилам.Я подумал, что было бы разумно создать класс со всеми свойствами и создать сетку экземпляров этого класса.(Поскольку я неопытен в Python, это может быть не очень хорошая идея, поэтому не стесняйтесь комментировать мой подход.)

Вот забавный пример того, что я делаю

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

Теперь я хочу иметь дело с двумерной / трехмерной решеткой (сеткой) таких сайтов, поэтому я попытался сделать следующее (здесь в качестве примера двумерная сетка 3х3, но при моделировании мне потребуется порядок>1000x1000X1000)

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

Теперь проблема в том, что каждая точка решетки ссылается на один и тот же экземпляр, например,

lattice[0,0].set_a(5)

также установит значение решетки [0,2].от а до 5. Такое поведение нежелательно.Чтобы избежать этой проблемы, я могу зациклить каждую точку сетки и назначить объекту элемент за элементом, например

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

Но есть ли лучший способ (без использования циклов) назначать объекты многомерному массиву?

Спасибо

Ответы [ 3 ]

26 голосов
/ 02 февраля 2011

Вы можете векторизовать функцию класса __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, который может привести к снижению производительности.

6 голосов
/ 02 февраля 2011

Вам не хватает того, что Python рассматривает все как ссылку.(Есть некоторые «неизменяемые» объекты, строки, числа и кортежи, которые обрабатываются больше как значения.) Когда вы делаете

lattice[:,:] = site(3)

, вы говорите «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)

Циклический способ - это один из правильных способов сделать это.С массивными массивами это может быть вашим лучшим вариантом;со списками 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)непитоновский.Лучше устанавливать и получать атрибуты напрямую, а затем использовать декоратор @property, если вам ДЕЙСТВИТЕЛЬНО нужно запретить доступ на запись к атрибуту.

Также обратите внимание, что для классов Python стандартно писать с использованием CamelCase, а нев нижнем регистре.

5 голосов
/ 02 февраля 2011

Я не знаю лучше, но в качестве альтернативы явному набору циклов, вы могли бы написать

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

, который должен работать независимо от формы решетки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...