试图为非字符串复制Python的字符串实习功能

Dle*_*eep 6 python python-2.7

对于自我项目,我想做类似的事情:

class Species(object): # immutable.
    def __init__(self, id):
        # ... (using id to obtain height and other data from file)
    def height(self):
        # ...

class Animal(object): # mutable.

    def __init__(self, nickname, species_id):
        self.nickname = nickname
        self.species = Species(id)
    def height(self):
        return self.species.height()
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我真的不需要每个id有一个以上的Species(id)实例,但每次我创建一个具有该id的Animal对象时我都会创建一个,并且我可能需要多个比方说的Animal(somename, 3).

为了解决这个问题,我要做的是创建一个类,以便对于它的2个实例,让我们说a和b,以下总是如此:

(a == b) == (a is b)
Run Code Online (Sandbox Code Playgroud)

这是Python用字符串文字做的事情,称为实习.例:

a = "hello"
b = "hello"
print(a is b)
Run Code Online (Sandbox Code Playgroud)

该print将产生true(只要字符串足够短,如果我们直接使用python shell).

我只能猜测CPython是如何做到的(它可能涉及一些C魔法)所以我正在做我自己的版本.到目前为止我有:

class MyClass(object):

    myHash = {} # This replicates the intern pool.

    def __new__(cls, n): # The default new method returns a new instance
        if n in MyClass.myHash:
            return MyClass.myHash[n]

        self = super(MyClass, cls).__new__(cls)
        self.__init(n)
        MyClass.myHash[n] = self

        return self

    # as pointed out on an answer, it's better to avoid initializating the instance 
    # with __init__, as that one's called even when returning an old instance.
    def __init(self, n): 
        self.n = n

a = MyClass(2)
b = MyClass(2)

print a is b # <<< True
Run Code Online (Sandbox Code Playgroud)

我的问题是:

a)我的问题是否值得解决?因为我想要的Species对象应该是非常轻的并且可以调用Animal的最大次数,相当有限(想象一个口袋妖怪游戏:不超过1000个实例,顶部)

b)如果是,这是解决我问题的有效方法吗?

c)如果它无效,你能详细说明一个更简单/更清洁/更Pythonic的方法来解决这个问题吗?

Blc*_*ght 1

是的,实现__new__返回缓存对象的方法是创建有限数量实例的适当方法。如果您不希望创建大量实例,则可以仅__eq__按值而不是身份进行实现和比较,但这样做并没有什么坏处。

请注意,不可变对象通常应在 中完成所有初始化__new__,而不是__init__,因为后者是在对象创建后调用的。此外,__init__将在从 返回的类的任何实例上调用__new__,因此当您进行缓存时,每次返回缓存的对象时都会再次调用它。

另外,第一个参数__new__是类对象而不是实例,因此您可能应该命名它cls而不是(如果您愿意,您可以在方法的后面self使用self而不是!)。instance