覆盖 python 中的所有二元运算符(或其他尊重物理维度的方式)?
Override all binary operators (or other way to respect physics dimensions) in python?
我正在构建 类 从 float 继承的方法,以在某些化学计算中考虑维度。例如:
class volume(float):
def __init__(self, value):
float._init_(value)
现在我的目标是:
- 在普通浮点数和 volume 实例之间使用 + 或 - 时引发错误
- return 一个卷实例,只要在两个卷实例之间使用 + 或 - 即可
- return 卷实例,无论何时使用 *(从两侧)和使用 /(从左侧)
- 从左侧使用 / 时引发错误
- return 每当两个体积实例被分割时一个浮点数。
现在,我将从左到右覆盖所有这四个运算符(例如 _add_ 和 _radd_);
err='Only objects of type volume can be added or subtracted together'
def __add__(self,volume2):
if isinstance(volume2,volume): return volume(float(self)+volume2)
else: raise TypeError(err)
def __radd__(self,volume2):
if isinstance(volume2,volume): return volume(float(self)+volume2)
else: raise TypeError(err)
有没有更简单的方法来访问所有这些,或者至少有一个表达式来包含运算符的左右用法?
看来这道题主要是为了避免代码重复。关于乘法和除法,您的功能略有不同,可能必须显式编写单独的方法,但对于加法和减法相关的方法,以下技术可行。它本质上是 monkey-patching class,可以这样做,尽管您不应该尝试类似于 monkey-patch instances in [=38] =] 3.
classVolume
我按照惯例用大写V来命名
class Volume(float):
pass
def _make_wrapper(name):
def wrapper(self, other):
if not isinstance(other, Volume):
raise ValueError
return Volume(getattr(float, name)(self, other))
setattr(Volume, name, wrapper)
for _method in ('__add__', '__radd__',
'__sub__', '__rsub__',):
_make_wrapper(_method)
这些情况下的等效显式方法如下所示,因此请根据乘法/除法情况的需要进行调整,但请注意显式使用 float.__add__(self, other)
而不是 self + other
正如问题所暗示的您打算使用的(问题提到 volume(self+volume2)
的地方),这将导致无限递归。
def __add__(self, other):
if not isinstance(other, Volume):
raise ValueError
return Volume(float.__add__(self, other))
关于__init__
,我现在已经在上面去掉了,因为如果它只是调用float.__init__
,那么根本就不需要定义它(让它继承__init__
来自基数 class)。如果你想有一个 __init__
方法来初始化一些东西 else,那么是的你将 also 需要包含显式调用到 float.__init__
就像你在问题中所做的那样(尽管注意双下划线 - 在你试图调用 float._init_
的问题中)。
metaclass
是一种控制 class
构造方式的方法。
您可以使用 metaclasses
重载所有数学运算符,如下所示:
err='Only objects of type volume can be added or subtracted together'
class OverLoadMeta(type):
def __new__(meta,name,bases,dct):
# this is the operation you want to use instead of default add or subtract.
def op(self,volume2):
if isinstance(volume2,Volume):
return Volume(float.__add__(self,volume2))
else:
raise TypeError(err)
# you can overload whatever method you want here
for method in ('__add__','__radd__','__sub__'):
dct[method] = op
return super(OverLoadMeta, meta).__new__(meta, name, bases, dct)
class Volume(float,metaclass=OverLoadMeta):
""
# you can use it like this:
a = Volume(1)
b = Volume(2)
c = a+b
print(c.__class__)
# class will be <class '__main__.Volume'>
a + 1
# raise TypeError: Only objects of type volume can be added or subtracted together
我正在构建 类 从 float 继承的方法,以在某些化学计算中考虑维度。例如:
class volume(float):
def __init__(self, value):
float._init_(value)
现在我的目标是:
- 在普通浮点数和 volume 实例之间使用 + 或 - 时引发错误
- return 一个卷实例,只要在两个卷实例之间使用 + 或 - 即可
- return 卷实例,无论何时使用 *(从两侧)和使用 /(从左侧)
- 从左侧使用 / 时引发错误
- return 每当两个体积实例被分割时一个浮点数。
现在,我将从左到右覆盖所有这四个运算符(例如 _add_ 和 _radd_);
err='Only objects of type volume can be added or subtracted together'
def __add__(self,volume2):
if isinstance(volume2,volume): return volume(float(self)+volume2)
else: raise TypeError(err)
def __radd__(self,volume2):
if isinstance(volume2,volume): return volume(float(self)+volume2)
else: raise TypeError(err)
有没有更简单的方法来访问所有这些,或者至少有一个表达式来包含运算符的左右用法?
看来这道题主要是为了避免代码重复。关于乘法和除法,您的功能略有不同,可能必须显式编写单独的方法,但对于加法和减法相关的方法,以下技术可行。它本质上是 monkey-patching class,可以这样做,尽管您不应该尝试类似于 monkey-patch instances in [=38] =] 3.
classVolume
我按照惯例用大写V来命名
class Volume(float):
pass
def _make_wrapper(name):
def wrapper(self, other):
if not isinstance(other, Volume):
raise ValueError
return Volume(getattr(float, name)(self, other))
setattr(Volume, name, wrapper)
for _method in ('__add__', '__radd__',
'__sub__', '__rsub__',):
_make_wrapper(_method)
这些情况下的等效显式方法如下所示,因此请根据乘法/除法情况的需要进行调整,但请注意显式使用 float.__add__(self, other)
而不是 self + other
正如问题所暗示的您打算使用的(问题提到 volume(self+volume2)
的地方),这将导致无限递归。
def __add__(self, other):
if not isinstance(other, Volume):
raise ValueError
return Volume(float.__add__(self, other))
关于__init__
,我现在已经在上面去掉了,因为如果它只是调用float.__init__
,那么根本就不需要定义它(让它继承__init__
来自基数 class)。如果你想有一个 __init__
方法来初始化一些东西 else,那么是的你将 also 需要包含显式调用到 float.__init__
就像你在问题中所做的那样(尽管注意双下划线 - 在你试图调用 float._init_
的问题中)。
metaclass
是一种控制 class
构造方式的方法。
您可以使用 metaclasses
重载所有数学运算符,如下所示:
err='Only objects of type volume can be added or subtracted together'
class OverLoadMeta(type):
def __new__(meta,name,bases,dct):
# this is the operation you want to use instead of default add or subtract.
def op(self,volume2):
if isinstance(volume2,Volume):
return Volume(float.__add__(self,volume2))
else:
raise TypeError(err)
# you can overload whatever method you want here
for method in ('__add__','__radd__','__sub__'):
dct[method] = op
return super(OverLoadMeta, meta).__new__(meta, name, bases, dct)
class Volume(float,metaclass=OverLoadMeta):
""
# you can use it like this:
a = Volume(1)
b = Volume(2)
c = a+b
print(c.__class__)
# class will be <class '__main__.Volume'>
a + 1
# raise TypeError: Only objects of type volume can be added or subtracted together