<p>如果您真的需要,子类化<code>int</code>可能是最好的方法,但是到目前为止显示的实现还很幼稚。我会这样做:</p>
<pre><code>class NegativeValueError(ValueError):
pass
class PositiveInteger(int):
def __new__(cls, value, base=10):
if isinstance(value, basestring):
inst = int.__new__(cls, value, base)
else:
inst = int.__new__(cls, value)
if inst < 0:
raise NegativeValueError()
return inst
def __repr__(self):
return "PositiveInteger({})".format(int.__repr__(self))
def __add__(self, other):
return PositiveInteger(int.__add__(self, other))
# ... implement other numeric type methods (__sub__, __mul__, etc.)
</code></pre>
<p>这允许您构造<code>PositiveInteger</code>,就像普通的<code>int</code>:</p>
^{pr2}$
<p>有关需要实现的方法的详细信息,请参见<a href="https://docs.python.org/2/reference/datamodel.html#emulating-numeric-types" rel="nofollow">the datamodel docs on numeric type emulation</a>。注意,在大多数方法中,您不需要显式地检查负数,因为当您<code>return PositiveInteger(...)</code>,<code>__new__</code>将为您检查。使用中:</p>
<pre><code>>>> i = PositiveInteger(5)
>>> i + 3
PositiveInteger(8)
</code></pre>
<hr/>
<p>或者,如果这些非负整数将是类的属性,则可以使用<a href="https://docs.python.org/2/howto/descriptor.html" rel="nofollow"><em>descriptor protocol</em></a>强制使用正值,例如:</p>
<pre><code>class PositiveIntegerAttribute(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, typ=None):
return getattr(obj, self.name)
def __set__(self, obj, val):
if not isinstance(val, (int, long)):
raise TypeError()
if val < 0:
raise NegativeValueError()
setattr(obj, self.name, val)
def __delete__(self, obj):
delattr(obj, self.name)
</code></pre>
<p>然后,您可以按如下方式使用:</p>
<pre><code>>>> class Test(object):
foo = PositiveIntegerAttribute('_foo')
>>> t = Test()
>>> t.foo = 1
>>> t.foo = -1
Traceback (most recent call last):
File "<pyshell#34>", line 1, in <module>
t.foo = -1
File "<pyshell#28>", line 13, in __set__
raise NegativeValueError()
NegativeValueError
>>> t.foo += 3
>>> t.foo
4
>>> t.foo -= 5
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
t.foo -= 5
File "<pyshell#28>", line 13, in __set__
raise NegativeValueError()
NegativeValueError
</code></pre>