我想创建一个带有边界的int类型:
> a = BoundInt(2,4)
a
只会保留值2,3或4,如果为其分配了不同的值,则会引发错误。
但是因为Python不允许我覆盖赋值并且使用setter不是Pythonic我有点迷失。
我如何在课堂上解决这个问题,以及在为我的vars分配新值时需要具体的语法?
答案 0 :(得分:3)
假设您尝试将此作为属性附加到类
您可以通过财产来执行此操作:
class Foo(object):
def __init__(self, a):
self._a = a
@property
def a(self):
return self._a
@a.setter
def a(self, value):
if not (2 <= value <= 4):
raise ValueError
self._a = value
请注意,我是使用setter。 Python样式通常不鼓励在属性访问时使用函数。但是,如果您在设置变量时需要采取某些操作,那么传统的setter或属性就可以了(取决于您要公开的API)。
如果您真的想使用类似于您已经编写的语法来执行此操作,可能使用描述符:
class BoundInt(object):
def __init__(self, lower, upper, name):
self.lower = lower
self.upper = upper
self.name = '_' + name
def __get__(self, inst, cls):
return getattr(inst, self.name)
def __set__(self, inst, val):
if self.lower <= val <= self.upper:
setattr(inst, self.name, val)
else:
raise ValueError('must be in bounds!')
class Foo(object):
a = BoundInt(2, 4, 'a')
f = Foo()
f.a = 2
print(f.a)
f.a = 3
print(f.a)
f.a = 4
print(f.a)
f.a = 5
结果:
2
3
4
Traceback (most recent call last):
File "/usr/home/mgilson/sandbox/test.py", line 28, in <module>
f.a = 5
File "/usr/home/mgilson/sandbox/test.py", line 15, in __set__
raise ValueError('must be in bounds!')
ValueError: must be in bounds!
答案 1 :(得分:0)
您可以使用属性:
class BoundInt(object):
def __init__(self, bottom, top):
self.bounds = range(bottom, top) # xrange for Python 2.x
self._value = bottom
@property
def value():
return self._value
@value.setter
def value(x):
if x in self.bounds:
self._value = x
else:
raise ValueError("%s is not in %r" % (x, self.bounds))
问题在于,您必须将您的值保存为对象的属性,然后实现允许您将其用作数字的int
的所有方法。在Python中,这基本上是不可避免的。
答案 2 :(得分:0)
您可以继承int
:
class BoundInt(int):
def __init__(self, x, allowed=(2, 3, 4), *args, **kwargs):
value = int(x, *args, **kwargs)
if value not in allowed:
raise ValueError("Not in allowed values: " + repr(allowed))
else:
self = value
a = BoundInt(2)
print a + 3
b = BoundInt('11', base=2)
print b - a
c = BoundInt(7)
请注意,您无法阻止Python assigment
或值名称。运算符=
仅将现有对象(右手表达式的值)绑定到变量名称。在Python中,它是值,具有类型,而不是变量名。