在Python中赋值后触发操作的正确方法是什么?

时间:2014-10-28 22:15:30

标签: python types

我想创建一个带有边界的int类型:

> a = BoundInt(2,4)

a只会保留值2,3或4,如果为其分配了不同的值,则会引发错误。

但是因为Python不允许我覆盖赋值并且使用setter不是Pythonic我有点迷失。

我如何在课堂上解决这个问题,以及在为我的vars分配新值时需要具体的语法?

3 个答案:

答案 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中,它是值,具有类型,而不是变量名。