如何在Python中创建具有高度限制实例的类

2 投票
7 回答
3445 浏览
提问于 2025-04-15 12:59

在Python中,有一些内置的类,它们的实例数量非常有限。比如,“None”是它所属类的唯一实例,而在布尔类中,只有两个对象,“True”和“False”(我希望我说的基本正确)。

另一个好的例子是整数:如果a和b都是int类型的实例,那么a == b就意味着a和b其实是同一个东西。

这里有两个问题:

  1. 怎么创建一个实例数量有限的类呢?比如,我们可以想要一个恰好有5个实例的类。或者像int类型那样,可以有无穷多个实例,但这些实例不是随便的。

  2. 如果整数形成一个类,为什么int()会返回0这个实例?这和一个用户自定义的类Cl相比,Cl()会返回这个类的一个实例,而不是一个特定的唯一实例,像0那样。难道int()不应该返回一个未指定的整数对象,也就是一个没有具体值的整数吗?

7 个回答

3

对于第一个问题,你可以使用单例模式来设计一个类,这种模式可以限制类的实例数量。你可以了解更多关于单例模式的信息,参考这个链接:http://en.wikipedia.org/wiki/Singleton_pattern

对于第二个问题,我觉得这个链接可以帮助你理解你的问题:http://docs.python.org/library/stdtypes.html

因为整数是有类型的,所以它们是有一些限制的。

这里还有一个资源可以参考... http://docs.python.org/library/functions.html#built-in-funcs

4

看起来第一个问题已经有很好的回答了,我想解释一个跟第二个问题有关的原则,这个原则似乎被所有回答者忽略了:对于大多数内置类型,当你不传参数调用这个类型时(也就是“默认构造函数”),它会返回一个该类型的实例,这个实例的值被认为是假的。也就是说,对于容器类型,它会返回一个空的容器;对于数字类型,它会返回一个等于零的数字。

>>> import decimal
>>> decimal.Decimal()
Decimal("0")
>>> set()
set([])
>>> float()
0.0
>>> tuple()
()
>>> dict()
{}
>>> list()
[]
>>> str()
''
>>> bool()
False

明白了吗?确实很常见!而且,对于可变类型,比如大多数容器,每次调用这个类型都会返回一个新的实例;而对于不可变类型,比如数字和字符串,情况就不一样了(可能会有内部优化,返回一个现有不可变实例的新引用,但这并不是必须的,若有这样的优化,通常会很有选择性地进行)。因为不可变类型的实例不能用 is 或者 id() 来比较。

如果你设计了一种类型,其中某些实例的值可以被认为是假的(通过在类中定义 __len____nonzero__ 特殊方法),那么建议你遵循同样的原则(如果调用 __init__ [或者对于不可变类型的 __new__] 时不带参数 [[当然除了 self 对于 __init__ 和 'cls' 对于 __new__]],就准备一个[[新的,如果是可变的]]“空”或“零值”实例)。

5

你提到的是给一个类赋予值语义,这通常是通过正常的方式创建类的实例来实现的,但要记住每一个实例。如果要创建一个匹配的实例,就返回已经创建的那个实例。在Python中,可以通过重载类的__new__ 方法来实现这一点。

举个简单的例子,假设我们想用一对整数来表示坐标,并且希望有正确的值语义。

class point(object):
    memo = {}
    def __new__(cls, x, y):
        if (x, y) in cls.memo:         # if it already exists, 
            return cls.memo[(x, y)]    # return the existing instance
        else:                          # otherwise, 
            newPoint = object.__new__(cls) # create it, 
            newPoint.x = x             # initialize it, as you would in __init__
            newPoint.y = y             
            cls.memo[(x, y)] = newPoint # memoize it, 
            return newPoint            # and return it!

撰写回答