假设我构建了一个基本上代表数字加上一些奇特东西的类.在任何算术/数学运算中,该类的实例应该像数字一样.
我可以重载该类中的所有数字运算符,但是没有更短的解决方案吗?
该课程基本上如下:
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
Run Code Online (Sandbox Code Playgroud)
那这个呢?
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'
Run Code Online (Sandbox Code Playgroud)
我想根据上述情况,你可以弄清楚你需要什么.
我不认为这是特别惯用的,但是......
假设您的所有函数定义的行为都相同,例如“只调用类的基本行为self.num并将所有非自参数应用于它”,那么您可以遍历要定义的所有函数名称,并使用创建每个函数名称setattr. 例子:
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)
Run Code Online (Sandbox Code Playgroud)
结果:
MyFancyNumber(60, 'hello')
MyFancyNumber(40, 'hello')
MyFancyNumber(500, 'hello')
MyFancyNumber(5, 'hello')
MyFancyNumber(-51, 'hello')
MyFancyNumber(-50, 'hello')
MyFancyNumber(50, 'hello')
Run Code Online (Sandbox Code Playgroud)
编辑:我不确定您希望算术结果是 MyFancyNumber 还是常规的内置数字类型,但无论哪种方式,实现都非常相似:
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)
Run Code Online (Sandbox Code Playgroud)
结果:
60
40
500
5
-51
-50
50
Run Code Online (Sandbox Code Playgroud)
不,你必须定义所有算术运算符,否则 Python 如何知道如何处理它们。不要忘记您还需要反向运算符,例如__radd__.
您编写的代码也会返回一个intfor x+1。您是这个意思还是想添加一个奇特的数字以返回另一个奇特的数字?
你可以只是子类化int或float. 这样您就不必重新实现运算符,但每当您对值进行操作时,您仍然会失去特殊性。
更好的解决方案是将数值放在属性中,并在需要时显式转换为数字。您可以使用__int__()和__float__()来实现转换。
该文档涵盖了如果您确实想要模拟数字类型,则需要执行的操作:对于 Python 3.x https://docs.python.org/3/reference/datamodel.html?highlight= int #emulated-numeric-类型或 Python 2.x https://docs.python.org/2/reference/datamodel.html?highlight= int #emulated-numeric-types