2013-07-15 13 views
5

Tôi cố gắng để làm cho công tác điều sau đây nhưng không thành công:Trong python, Làm thế nào để thực hiện đúng toán hạng có mức ưu tiên (của phương thức __rmul__) khi nhân hai lớp khác nhau?

tôi định nghĩa kiểu của riêng tôi Unit (kế thừa từ build-in loại float) để thực hiện đại số cho số lượng với các đơn vị. Nó làm mọi thứ theo cách mà:

class Unit(float): 
"""provide a simple unit converter for a given quantity""" 

    def __new__(cls, unit, num=1.): 
     return super(Unit, cls).__new__(cls, num) 

    def __init__(self, unit, num=1.): 
     """set up base unit""" 
     self.unit = unit 

    def __str__(self,): 
     return '{:s} {:s}'.format(super(Unit, self).__str__(), self.unit) 

    def __rmul__(self, other): 
     print 'rmul: {:f}'.format(super(Unit, self).__rmul__(other)) 
     return Unit(self.unit, super(Unit, self).__rmul__(other)) 

    def to(self,target): 
     fun_conv = _conv(self.unit, target) 
     return Unit(target, num=fun_conv(self)) 



c = 3e8 * Unit('m/s') # this will 1) create a Unit instance with magnitude '1' and unit 'm/s', 
         #   2) invoke __rmul__ to return a new instance with number 3e8 and unit 'm/s' to variable 'c' 
print c.to('km/s')  # returns 3e5 km/s 

Tuy nhiên, __rmul__ này chỉ được gọi khi float là toán hạng bên trái. Nếu tôi làm một cái gì đó như thế này:

velocities = np.array([20, 10]) * Unit('m/s') 

Sau đó Unit.__rmul__ sẽ không được gọi, và cùng numpy ndarray được trả lại kể từ bây giờ Unit('m/s') được đối xử như một đồng bằng float với giá trị 1,0

Những gì tôi mong đợi là: sau khi ndarray * Unit , một hàm tương tự như Unit.to có thể được attacted thành cá thể của ndarray như một phương thức cũng như một thuộc tính unit, vì vậy tôi có thể gọi thêm ndarray.to để trả về một bản sao (hoặc phiên bản sửa đổi, nếu có thể, để hiệu quả bộ nhớ) của bản gốc ndarray kết hợp với các giá trị và đơn vị mới. Làm cách nào để tiếp tục?

Theo những gì tôi đã biết và đã tìm kiếm, __mul__ của toán hạng bên trái sẽ có trước trong *, ví dụ: kiểm tra thông dịch LO.__mul__() đầu tiên, nếu nó không thành công, sau đó đi vào RO.__rmul__(). Tôi không hoàn toàn muốn ghi đè lên numpy.ndarray.__mul__ vì tôi thực sự không biết nó sẽ phức tạp như thế nào, và liệu sẽ có một mớ hỗn độn lớn trong trường hợp nó phá vỡ các quy tắc không hoạt động trên các đối tượng khác.

Và, thực sự tôi thậm chí không thể tìm thấy các mã xác định __mul__ cho ndarray. Tôi chỉ đơn giản sử dụng inspect.getsource(np.ndarray) nhưng không thành công. Tại sao nó thất bại về điều này? ngoại lệ chỉ là một số IOError.

Cảm ơn bạn rất nhiều vì sự quan tâm của bạn!

+2

bạn có cân nhắc rằng trong scipy.constants.physical_constants, bạn cũng thấy tốc độ ánh sáng v.v ... không? http://docs.scipy.org/doc/scipy/reference/constants.html Họ cũng có các đơn vị, nhưng tôi không thực sự biết cách hỗ trợ nhân với các đơn vị vv, nhưng tôi đoán điều này có thể chỉ cho bạn ở bên phải hướng cho không tái phát minh bánh xe nếu bạn nhận được ý nghĩa của tôi – usethedeathstar

+0

Tôi chỉ cần làm một kiểm tra nhanh chóng về điều đó nhưng có vẻ như không có chuyển đổi cường độ/thông lượng được hỗ trợ. Và nó trông quá đơn giản. Những gì tôi cuối cùng muốn làm là để làm cho có thể làm việc với nhiều chuyển đổi phi tuyến tính, cũng như tuyên truyền lỗi hoặc một cái gì đó tương tự. Và bây giờ tôi đang học nên tôi không bận tâm để phát minh lại bánh xe. Nhưng cảm ơn tất cả các bạn! –

+1

Đây là một ví dụ khác về lý do tại sao bạn không nên ** kế thừa từ các kiểu tích hợp sẵn. Bạn nghĩ rằng phân lớp chúng là tốt vì bạn chỉ có thể sửa đổi một số phương pháp và bạn đã hoàn thành, nhưng * điều này là sai *. * mọi lúc * bạn phân lớp một built-in bạn * phải * tái triển khai * mọi phương thức *, * cộng * thực hiện các phương thức '__r * __', nếu không thì * sẽ * là lỗi. Do đó nó chỉ đơn giản hơn để sử dụng thành phần. – Bakuriu

Trả lời

2

Nếu bạn không hít phải phao, nhưng thay vào đó hãy tạo phao bọc kiểu mới (để float._ mul _ (yourtype) không hoạt động), rmul sẽ làm những gì bạn muốn. Các gói sẽ tất nhiên không được miễn phí, mặc dù ... và bạn sẽ phải thực hiện tất cả các hoạt động bạn muốn loại hỗ trợ.

class T(object): 
    def __init__(self, val): 
    self.val = val 

    def __mul__(self, x): 
    print("mul") 
    return T(self.val*x) 

    def __rmul__(self, x): 
    print("rmul") 
    return T(self.val*x) 

    def __repr__(self): 
    return str(self.val) 

>>> t = T(2) 
>>> t * 2 
mul 
4 
>>> 2*t 
rmul 
4 
Các vấn đề liên quan