修饰算术运算符 |我应该使用元类吗?
我想实现一个对象,在对其应用算术运算后将值限制在给定范围内。下面的代码工作正常,但我毫无意义地重写了这些方法。当然有一种更优雅的方法来做到这一点。元类是正确的选择吗?
def check_range(_operator):
def decorator1(instance,_val):
value = _operator(instance,_val)
if value > instance._upperbound:
value = instance._upperbound
if value < instance._lowerbound:
value = instance._lowerbound
instance.value = value
return Range(value, instance._lowerbound, instance._upperbound)
return decorator1
class Range(object):
'''
however you add, multiply or divide, it will always stay within boundaries
'''
def __init__(self, value, lowerbound, upperbound):
'''
@param lowerbound:
@param upperbound:
'''
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def init(self):
'''
set a random value within bounds
'''
self.value = random.uniform(self._lowerbound, self._upperbound)
def __str__(self):
return self.__repr__()
def __repr__(self):
return "<Range: %s>" % (self.value)
@check_range
def __mul__(self, other):
return self.value * other
@check_range
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self.div(other)
@check_range
def __add__(self, other):
return self.value + other
@check_range
def __sub__(self, other):
return self.value - other
I'd like to implement an object, that bounds values within a given range after arithmetic operations have been applied to it. The code below works fine, but I'm pointlessly rewriting the methods. Surely there's a more elegant way of doing this. Is a metaclass the way to go?
def check_range(_operator):
def decorator1(instance,_val):
value = _operator(instance,_val)
if value > instance._upperbound:
value = instance._upperbound
if value < instance._lowerbound:
value = instance._lowerbound
instance.value = value
return Range(value, instance._lowerbound, instance._upperbound)
return decorator1
class Range(object):
'''
however you add, multiply or divide, it will always stay within boundaries
'''
def __init__(self, value, lowerbound, upperbound):
'''
@param lowerbound:
@param upperbound:
'''
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def init(self):
'''
set a random value within bounds
'''
self.value = random.uniform(self._lowerbound, self._upperbound)
def __str__(self):
return self.__repr__()
def __repr__(self):
return "<Range: %s>" % (self.value)
@check_range
def __mul__(self, other):
return self.value * other
@check_range
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self.div(other)
@check_range
def __add__(self, other):
return self.value + other
@check_range
def __sub__(self, other):
return self.value - other
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
可以使用元类将装饰器应用于一组函数名称,但我认为这不是您的情况的方法。正如您所做的那样,使用
@decorator
语法在类主体中逐个函数地应用装饰器,我认为这是一个非常好的选择。 (我认为你的装饰器中有一个错误,顺便说一句:你可能不想将instance.value
设置为任何内容;算术运算符通常不会改变其操作数)。我可能在您的情况下使用的另一种方法(避免装饰器一起使用)是执行以下操作:
打印
我建议您在这种情况下不要使用元类,但这是一种可以的方法。元类是一个有用的工具,如果您有兴趣,最好了解如何在真正需要它们时使用它们。
It is possible to use a metaclass to apply a decorator to a set of function names, but I don't think that this is the way to go in your case. Applying the decorator in the class body on a function-by-function basis as you've done, with the
@decorator
syntax, I think is a very good option. (I think you've got a bug in your decorator, BTW: you probably do not want to setinstance.value
to anything; arithmetic operators usually don't mutate their operands).Another approach I might use in your situation, kind of avoiding decorators all together, is to do something like this:
printing
I suggest that you do NOT use a metaclass in this circumstance, but here is one way you could. Metaclasses are a useful tool, and if you're interested, it's nice to understand how to use them for when you really need them.
正如关于元类的明智说法:如果您想知道是否需要它们,那么您就不需要。
我不完全理解你的问题,但我会创建一个 BoundedValue 类,并且我们只将所述类的实例放入你提议的类中。
当然,您可以(并且应该)更改您正在寻找的实际行为的断言;您还可以更改构造函数以包含初始化值。我选择通过属性
val
将其设置为构造后赋值。拥有此对象后,您可以创建类并使用 BoundedValue 实例,而不是
float
或int
。As it is wisely said about metaclasses: if you wonder wether you need them, then you don't.
I don't fully understand your problem, but I would create a
BoundedValue
class, and us only instances of said class into the class you are proposing.Of course you could (and should) change the
assert
ion for the actual behavior you are looking for; also you can change the constructor to include the initialization value. I chose to make it an assignment post-construction via the propertyval
.Once you have this object, you can create your classes and use BoundedValue instances, instead of
float
s orint
s.