2017-02-27 17 views
9

Giả sử tôi xây dựng một lớp cơ bản đại diện cho một số cộng với một số công cụ ưa thích. Các cá thể của lớp đó sẽ hoạt động giống như các số trong bất kỳ phép toán số học/toán học nào.Quá tải tất cả toán tử số học trong Python

Tôi có thể quá tải tất cả toán tử số trong lớp đó, nhưng không có giải pháp ngắn hơn?

Lớp cơ bản trông giống như:

class MyFancyNumber: 
    def __init__(self, num, info): 
     self.num = num # the actual number 
     self.info = info # some more info, or other data 
    def doFancyStuff(self): 
     # does something fancy 
    def __add__(self, other): 
     return self.num + other # same pattern for all numeric functions 
+1

https://docs.python.org/3/library/numbers.html Điều này có thể giúp bạn bắt đầu. –

+1

Sử dụng '__add__' theo cách này có thể không làm những gì bạn muốn. 'MyFancyNumber (1, 'abc') + 1' sẽ cho bạn một đối tượng' int', không phải là 'MyFancyNumber'. –

+1

Theo như tôi hiểu, anh ta không muốn trả lại MyFancyNumber, anh ta chỉ muốn có tất cả các chức năng như một số trong thuật ngữ của các toán tử. – Szabolcs

Trả lời

1

Không, bạn phải xác định tất cả các toán tử số học nếu không làm thế Python sẽ biết phải làm gì với họ. Đừng quên bạn cũng cần các toán tử đảo ngược như __radd__.

Ngoài ra mã bạn đã viết trả về int cho x+1. Ý của bạn là bạn có muốn thêm một số ưa thích để trả về một số ưa thích khác không?

Bạn chỉ có thể phân lớp int hoặc float. Sau đó, bạn không phải reimplement các nhà khai thác nhưng bạn vẫn sẽ mất tính chất đặc biệt bất cứ khi nào bạn hoạt động trên một giá trị.

Một giải pháp tốt hơn sẽ chỉ là có giá trị số trong thuộc tính và chuyển đổi thành số một cách rõ ràng khi đó là những gì bạn muốn. Bạn có thể sử dụng __int__()__float__() để triển khai chuyển đổi.

Các tài liệu bao gồm những gì bạn cần phải làm gì nếu bạn thực sự muốn bắt chước một số loại: cho Python 3.x https://docs.python.org/3/reference/datamodel.html?highlight=int#emulating-numeric-types hoặc cho Python 2.x https://docs.python.org/2/reference/datamodel.html?highlight=int#emulating-numeric-types

7

gì về điều này?

class MyFancyNumber(int): 
    def __new__(cls, num, info=None): 
     return super(MyFancyNumber, cls).__new__(cls, num) 
    def __init__(self, num, info=None): 
     self.num = num 
     self.info = info 
>>> MyFancyNumber(5) 
5 
>>> MyFancyNumber(5) + 2 
7 
>>> MyFancyNumber(5)/4 
1 
>>> MyFancyNumber(5) * 0.5 
2.5 
>>> MyFancyNumber(5) - 7 
-2 
>>> MyFancyNumber(5, 'info').info 
'info' 

Tôi đoán dựa trên ở trên, bạn có thể tìm ra những gì bạn cần.

+0

Sẽ tốt hơn nếu bạn đưa thêm tham số vào ví dụ của mình. Ngoài ra điều này có cùng một vấn đề như bản gốc mà bạn bị mất lớp con trên bất kỳ hoạt động nào có thể hoặc có thể không là những gì họ muốn. – Duncan

+0

Ông muốn các trường hợp của lớp đó sẽ hoạt động như các số trong bất kỳ phép toán số học/toán học nào. – Szabolcs

+0

Một lợi thế mà cách tiếp cận này có trên phương pháp tiếp cận của tôi, là bạn không cần phải liệt kê đầy đủ thông qua mọi toán tử mà bạn muốn xác định. Không thức dậy trong một mồ hôi lạnh một tháng sau đó hét lên "Tôi quên thực hiện' __radd__'! " ;-) – Kevin

0

Điều này làm việc cho tôi trong python 2.7 miễn là bạn chỉ vượt qua một đối số trong init. Đáng buồn thay không có ý tưởng tại sao nó hoạt động mặc dù.

class MyFancyNumber(int): 
    def __init__(self, num): 
     self.num = num # the actual number 

    def add_info(self,info): 
     self.info = info ## Add the info separately 

    def doFancyStuff(self): 
     # does something fancy 

print MyFancyNumber(5)+5  

Cách sử dụng

f = MyFancyNumber(2) 
f.add_info(info) 
f+4    ## returns 6 
2

Tôi không tán thành điều này như là đặc biệt thành ngữ, nhưng ...

Giả sử tất cả các định nghĩa chức năng của bạn cư xử hệt như "chỉ cần gọi các hành vi cơ sở của lớp self.num và áp dụng tất cả các đối số không tự đối với nó ", sau đó bạn có thể lặp qua tất cả các tên hàm bạn muốn xác định và tạo từng tên bằng cách sử dụng setattr.Ví dụ:

class MyFancyNumber(object): 
    def __init__(self, num, info): 
     self.num = num 
     self.info = info 
    def __repr__(self): 
     return "MyFancyNumber({}, {})".format(repr(self.num), repr(self.info)) 

def make_func(name): 
    return lambda self, *args: MyFancyNumber(getattr(self.num, name)(*args), self.info) 

for name in ["__add__", "__sub__", "__mul__", "__div__", "__invert__", "__neg__", "__pos__"]: 
    setattr(MyFancyNumber, name, make_func(name)) 

x = MyFancyNumber(50, "hello") 
print(x + 10) 
print(x - 10) 
print(x * 10) 
print(x/10) 
print(~x) 
print(-x) 
print(+x) 

Kết quả:

MyFancyNumber(60, 'hello') 
MyFancyNumber(40, 'hello') 
MyFancyNumber(500, 'hello') 
MyFancyNumber(5, 'hello') 
MyFancyNumber(-51, 'hello') 
MyFancyNumber(-50, 'hello') 
MyFancyNumber(50, 'hello') 

Chỉnh sửa: Tôi đã không chắc chắn cho dù bạn muốn kết quả của số học là một MyFancyNumber hoặc thường xuyên built-in loại số, nhưng một trong hai cách này, việc triển khai khá giống:

class MyFancyNumber(object): 
    def __init__(self, num, info): 
     self.num = num 
     self.info = info 
    def __repr__(self): 
     return "MyFancyNumber({}, {})".format(repr(self.num), repr(self.info)) 

def make_func(name): 
    return lambda self, *args: getattr(self.num, name)(*args) 

for name in ["__add__", "__sub__", "__mul__", "__div__", "__invert__", "__neg__", "__pos__"]: 
    setattr(MyFancyNumber, name, make_func(name)) 

x = MyFancyNumber(50, "hello") 
print(x + 10) 
print(x - 10) 
print(x * 10) 
print(x/10) 
print(~x) 
print(-x) 
print(+x) 

Kết quả:

60 
40 
500 
5 
-51 
-50 
50 
+0

nó có thể không đặc biệt thành ngữ, nhưng chắc chắn là có lập trình – ofloveandhate