2011-02-02 52 views
18

Tôi đang cố gắng thực hiện mô phỏng cho một mô hình mạng (lattice boltzmann) trong Python. Mỗi trang web của mạng có một số thuộc tính và tương tác với các trang web lân cận theo các quy tắc nhất định. Tôi nghĩ rằng nó có thể là thông minh để làm cho một lớp học với tất cả các thuộc tính và tạo ra một mạng lưới các trường hợp của lớp đó. (Như tôi thiếu kinh nghiệm với Python, điều này có thể không phải là một ý tưởng tốt ở tất cả, vì vậy cảm thấy tự do để nhận xét về cách tiếp cận của tôi.)mảng nhiều đối tượng

Dưới đây là một ví dụ đồ chơi về những gì tôi đang làm

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

Bây giờ tôi muốn đối phó với một mạng lưới 2D/3D của các trang web như vậy nên tôi đã cố gắng làm như sau (đây là một lưới 3x3 2D làm ví dụ, nhưng trong mô phỏng tôi sẽ cần thứ tự> 1000x1000X1000)

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

Bây giờ, vấn đề là mỗi điểm mạng tham chiếu đến cùng một trường hợp, ví dụ:

lattice[0,0].set_a(5) 

cũng sẽ đặt giá trị của mạng [0,2] .a thành 5. Hành vi này không mong muốn. Để tránh những vấn đề tôi có thể lặp qua mỗi điểm lưới và gán các yếu tố đối tượng bởi yếu tố, như

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

Nhưng có một cách tốt hơn (không liên quan đến các vòng) để gán đối tượng đến một mảng đa chiều?

Cảm ơn

+7

Nếu bạn đang xử lý một mảng> 1000x1000X1000, _don't_ sử dụng mảng đối tượng !! Nó sẽ sử dụng lượng bộ nhớ khổng lồ so với việc sử dụng một mảng numpy "bình thường". Đối tượng mảng không phải là những gì bạn muốn ở đây ... –

+4

bằng cách mô phỏng tôi đoán bạn có nghĩa là mô phỏng chất lỏng? Nếu có, thì tôi sẽ khuyên bạn nên suy nghĩ lại cách tiếp cận của bạn. Có lẽ các phần tử của mảng của bạn phải là số, vì vậy bạn có thể khai thác tất cả sức mạnh của đại số tuyến tính ;-). Quá trình tuyên truyền và va chạm của hạt phải được thực hiện trên toàn cầu! Không có mạng đối tượng cục bộ nào có thể xử lý trong bất kỳ thời gian tính toán hợp lý nào. Chỉ cần khó khăn, không biết thực sự những gì bạn đang nhắm đến ;-). Cảm ơn – eat

+0

@eat: Tôi đang làm mô phỏng chất lỏng. Tôi muốn mã một mạng lưới chung của các trang web, nơi tất cả các thuộc tính cục bộ được thu thập trong một lớp (va chạm là cục bộ trong cuốn sách của tôi, không phải là tuyên truyền tho), nhưng tôi đoán bạn là đúng sau khi tất cả. Ít nhất bpowah đã dạy tôi cách vector hóa hàm __init__ :) – jonalm

Trả lời

18

Bạn có thể vectorize chức năng của lớp __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) 

này có thể trông sạch hơn nhưng không có lợi thế hiệu suất so với giải pháp vòng lặp của bạn. Các câu trả lời về danh sách hiểu sẽ tạo ra một danh sách python trung gian sẽ gây ra một hit hiệu năng.

+0

Mẹo tuyệt vời. Cảm ơn. – jonalm

+0

+1. Ví dụ tốt đẹp cho vectorize. – tom10

+0

Điều gì xảy ra nếu 'Site' nhận nhiều hơn một tham số? –

6

Phần còn thiếu cho bạn là Python coi mọi thứ là tham chiếu. (Có một số "bất biến" các đối tượng, chuỗi và số và các bộ, được đối xử giống như giá trị.) Khi bạn làm

lattice[:,:] = site(3) 

bạn đang nói "Python: làm cho một đối tượng mới site, và nói với mọi phần tử của lattice để trỏ đến đối tượng đó. " Để thấy rằng đây thực sự là trường hợp, in mảng để xem rằng địa chỉ bộ nhớ của các đối tượng là như nhau:

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) 

Cách vòng lặp là một cách chính xác để thực hiện. Với mảng numpy, đó có thể là lựa chọn tốt nhất của bạn; với danh sách Python, bạn cũng có thể sử dụng danh sách hiểu:

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

Bạn có thể sử dụng danh sách hiểu với numpy.array xây dựng:

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

Bây giờ khi bạn in lattice, nó

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) 

để bạn có thể thấy rằng mọi đối tượng trong đó là duy nhất.

Bạn cũng nên lưu ý rằng các phương thức "setter" và "getter" (ví dụ: set_a) không phải là Pythonic. Tốt hơn là đặt và nhận thuộc tính trực tiếp và sau đó sử dụng trình trang trí @property nếu bạn THỰC SỰ cần ngăn chặn quyền ghi vào thuộc tính.

Cũng lưu ý rằng tiêu chuẩn cho các lớp Python được viết bằng CamelCase chứ không phải chữ thường.

+0

Cảm ơn bạn rất nhiều về đầu vào. Nhưng tôi không biết nếu tôi hiểu bạn một cách chính xác; Đối với một cá thể lớp A = trang web (4,5), có tốt hơn (nhiều Pythonic) để cập nhật biến với 'A.a = 6' hơn 'A.set_a (6)' không? Bất kỳ tài liệu tham khảo về hướng dẫn tốt để mã hóa pythonic? – jonalm

+0

Hãy cẩn thận với điều này là 'Site' thực hiện' __len__'. –

3

Tôi không biết về tốt hơn, nhưng như một thay thế cho một bộ rõ ràng của các vòng, bạn có thể viết

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

mà nên làm việc bất cứ hình dạng của các mạng.

Các vấn đề liên quan