2011-01-21 34 views
6

[Python 3]numpy.ndarray: chuyển sang một lớp học "bình thường"

Tôi thích ndarray nhưng tôi cảm thấy bực bội để sử dụng.

Đây là một vấn đề tôi gặp phải. Tôi muốn viết class Array sẽ kế thừa nhiều chức năng của ndarray, nhưng chỉ có một cách để được khởi tạo: như là một mảng không chứa đầy một kích thước nhất định. Tôi đã hy vọng để viết:

class Array(numpy.ndarray): 
    def __init__(size): 
    # What do here? 

Tôi muốn gọi super().__init__ với một số thông số để tạo ra một mảng zero-điền, nhưng nó sẽ không làm việc kể từ ndarray sử dụng một chức năng toàn cầu numpy.zeros (chứ không phải là một constructor) để tạo mảng không được lấp đầy.

Câu hỏi:

  1. Tại sao ndarray sử dụng toàn cầu chức năng (mô-đun) thay vì nhà xây dựng trong nhiều trường hợp? Đó là một khó chịu lớn nếu tôi đang cố gắng tái sử dụng chúng trong một thiết lập hướng đối tượng.

  2. Cách tốt nhất để xác định class Array mà tôi cần là gì? Tôi có nên điền thủ công ndarray bằng số không hoặc có cách nào để sử dụng lại chức năng zeros không?

+2

Tôi không hiểu tại sao bạn muốn tạo lớp của riêng mình. Lợi thế của chức năng nhà máy 'numpy.zeros()' là gì? Nếu bạn không thích tên, chỉ cần đổi tên nó, như 'create_array = numpy.zeros'. –

+0

Tôi không còn chắc chắn có lợi thế nữa. Có lẽ tôi không quen với chức năng của nhà máy. Tôi sẽ phải suy nghĩ về nó. – max

+0

@Sven Marnach: Tôi đã tìm thấy một số liên kết về chủ đề chung này: http://stackoverflow.com/questions/628950/constructors-vs-factory-methods http://stackoverflow.com/questions/2959871/factory -vs-instance-constructors http://stackoverflow.com/questions/4617311/creation-of-objects-constructors-or-static-factory-methods Không có gì cụ thể cho Python, nhưng các nhận xét chung từ các ngôn ngữ khác dường như ứng dụng. Và theo như tôi có thể nói, thực sự không có bất lợi cho chức năng của nhà máy (ngoài sở thích cá nhân của tôi). – max

Trả lời

6

Nếu bạn không thích giao diện ndarray sau đó không kế thừa nó. Bạn có thể xác định giao diện của riêng bạn và ủy quyền phần còn lại để ndarray và numpy.

import functools 
import numpy as np 


class Array(object): 

    def __init__(self, size): 
     self._array = np.zeros(size) 

    def __getattr__(self, attr): 
     try: return getattr(self._array, attr) 
     except AttributeError: 
      # extend interface to all functions from numpy 
      f = getattr(np, attr, None) 
      if hasattr(f, '__call__'): 
       return functools.partial(f, self._array) 
      else: 
       raise AttributeError(attr) 

    def allzero(self): 
     return np.allclose(self._array, 0) 


a = Array(10) 
# ndarray doesn't have 'sometrue()' that is the same as 'any()' that it has. 
assert a.sometrue() == a.any() == False 
assert a.allzero() 

try: a.non_existent 
except AttributeError: 
    pass 
else: 
    assert 0 
+0

Rất gọn gàng. Tôi giả sử rằng tất cả các hàm toàn cục 'numpy' đều có cùng ngữ nghĩa khi được gọi với đối số' ndarray' làm phương thức thể hiện cùng tên của 'ndarray'. – max

+0

Để thay đổi thành Python 3, tôi chỉ xóa '(đối tượng)' khỏi định nghĩa lớp, đúng không? [Không phải là để lại nó sẽ gây ra vấn đề.] – max

+0

@max: mã hoạt động mà không có thay đổi trên cả 2.x và Python 3. – jfs

7

Tại sao ndarray sử dụng toàn cầu chức năng (mô-đun) thay vì nhà xây dựng trong nhiều trường hợp?

  1. Để phù hợp/tương tự như Matlab, nơi các chức năng như zeros hoặc ones ban đầu đến từ đâu.
  2. Chức năng nhà máy toàn cầu được viết nhanh và dễ hiểu. Ngữ nghĩa của một hàm tạo nên là gì, ví dụ: làm thế nào bạn thể hiện một đơn giản zeros hoặc empty hoặc ones với một hàm tạo duy nhất? Trong thực tế, các chức năng của nhà máy như vậy là khá phổ biến, cũng bằng các ngôn ngữ lập trình khác.

Cách tốt nhất để xác định class Array mà tôi cần là gì?

import numpy 

class Array(numpy.ndarray): 
    def __new__(cls, size): 
     result = numpy.ndarray.__new__(Array, size) 
     result.fill(0) 
     return result 
arr = Array(5) 

def test(a): 
    print type(a), a 

test(arr) 
test(arr[2:4]) 
test(arr.view(int)) 

arr[2:4] = 5.5 

test(arr) 
test(arr[2:4]) 
test(arr.view(int)) 

Lưu ý rằng đây là Python 2, nhưng nó sẽ yêu cầu sửa đổi chỉ nhỏ để làm việc với Python 3.

+1

Một số nhận xét: 1. Tham số 'shape' đối với hàm tạo' ndarray' có thể chỉ đơn giản là một số nguyên thay vì một bộ tuple. 2. 'dtype = float' là mặc định. 3. Trong Python 3, bạn có thể bỏ qua các đối số cho 'super()' trong trường hợp này. Kết hợp những nhận xét này, hai dòng đầu tiên của hàm tạo giảm xuống thành 'super() .__ init __ (size)'. –

+0

Ồ, và tôi chỉ nhận thấy rằng lệnh 'super()' của bạn là sai - nên là 'super (Array, self)' trong Python 2.x. –

+0

Bạn nói đúng, tôi đã chỉnh sửa câu trả lời của tôi. (Chữ ký của hàm tạo là không có giấy tờ, như thường lệ.) – Philipp

4

Thừa kế của ndarray hơi phức tạp một chút. ndarray thậm chí không có phương thức __init(self,)___, do đó không thể gọi từ lớp con, nhưng có lý do cho điều đó. Vui lòng xem tài liệu có gumpy của subclassing.

Bằng cách này, bạn có thể cụ thể hơn về các nhu cầu cụ thể của mình không?Nó vẫn còn khá dễ dàng để nấu ăn một lớp (sử dụng ndarray) cho nhu cầu của riêng bạn, nhưng một phân lớp của ndarray để vượt qua tất cả các máy móc khó khăn là vấn đề khá khác nhau.

Dường như tôi không thể bình luận bài của riêng tôi, lẻ
@Philipp: Nó sẽ được gọi bằng Python, nhưng không phải bởi NumPy. Có ba cách để khởi tạo ndarray và hướng dẫn cách xử lý tất cả các trường hợp được đưa ra trên tài liệu đó.

+1

Tôi dường như đã bỏ lỡ tài liệu này. Nhưng tại sao phương thức '__init__' trong ví dụ của tôi được gọi mặc dù' ndarray' có '__new__'? – Philipp

+0

@Philipp: xem nhận xét của tôi cho câu trả lời của bạn. – max

+0

Tôi chỉ muốn lớp học của riêng mình mà tôi hoàn toàn kiểm soát cách nó được khởi tạo. Bạn đúng subclassing ndarray là quá khó. Tôi sẽ làm theo cách tiếp cận container trong @ J.F. Sebastian. – max

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