从类工厂返回的类具有不同的ID

时间:2018-01-16 21:13:24

标签: python python-3.x class factory-method

我有一个类工厂方法,用于实例化一个对象。通过此方法创建多个对象,我希望能够比较对象的类。使用isinstance时,比较结果为False,如下面的简单示例所示。同时运行id(a.__class__)id(b.__class__)会提供不同的ID。

有一种简单的方法可以实现这一目标吗?我知道这并不完全符合鸭子类型,但这是我写的程序最简单的解决方案。

def factory():
    class MyClass(object):
        def compare(self, other):
            print('Comparison Result: {}'.format(isinstance(other, self.__class__)))
    return MyClass()

a = factory()
b = factory()

print(a.compare(b))

4 个答案:

答案 0 :(得分:2)

原因是每次运行MyClass时动态创建factory。如果您在print(id(MyClass))factory得到不同的结果:

>>> a = factory()
140465711359728
>>> b = factory()
140465712488632

这是因为它们实际上是不同的类,在调用时动态创建和本地作用域。

解决此问题的一种方法是返回(或yield)多个实例:

>>> def factory(n):
    class MyClass(object):
        def compare(self, other):
            print('Comparison Result: {}'.format(isinstance(other, self.__class__)))
    for i in range(n):
        yield MyClass()


>>> a, b = factory(2)
>>> a.compare(b)
Comparison Result: True

是一种可能的实施方式。

编辑:如果动态创建实例,则上述解决方案无效。一种方法是在外部创建一个超类,然后在该超类的工厂函数子类中创建:

>>> class MyClass(object):
    pass

>>> def factory():
    class SubClass(MyClass):
        def compare(self, other):
            print('Comparison Result: {}'.format(isinstance(other, self.__class__)))
    return SubClass()

然而,这不起作用,因为它们仍然是不同的类。因此,您需要更改比较方法以检查第一个超类:

isinstance(other, self.__class__.__mro__[1])

答案 1 :(得分:2)

如果您的class定义在工厂函数内,则您创建的每个类的实例都将是一个单独的类的实例。这是因为class定义是一个声明,它的执行方式与任何其他任务一样。不同类的名称和内容将是相同的,但它们的身份将是截然不同的。

我不认为有任何简单的方法可以在不改变代码结构的情况下解决这个问题。您已经说过,您的实际工厂函数是一个类的方法,这表明您可以将类定义移动到其他位置,以便可以通过多次调用工厂方法来共享它。根据您希望内部类从外部类中使用的信息,您可以在类级别定义它(因此只有一个类定义在任何地方使用),或者您可以在另一个方法中定义它,例如{ {1}}(这将为外部类的每个实例创建一个新的内部类。)

这是最后一种方法的样子:

__init__

答案 2 :(得分:0)

你所要求的并不完全清楚。在我看来,你想要一个更简单的代码版本。如果这不正确,则此答案无关紧要。

您可以通过显式构建type类型的新实例来动态创建类。

def compare(self, other):
        ...

def factory():
    return type("MyClass", (object,), { 'compare': compare }()

type有三个参数:名称,父项和预定义的插槽。因此,这与您之前的代码的行为方式相同。

答案 3 :(得分:0)

解决@rassar的答案,并添加更多细节来表示实际的实现(例如父类中存在的工厂方法),我在下面提出了一个工作示例。

从@ rassar的回答中,我意识到每次动态创建类,因此在父对象(甚至高于该对象)中定义它,意味着每次调用它时它都是相同的类定义。 / p>

class Parent(object):
    class MyClass(object):
        def __init__(self, parent):
            self.parent = parent

        def compare(self, other):
            print('Comparison Result: {}'.format(isinstance(other, self.__class__)))

    def factory(self):
        return self.MyClass(self)


a = Parent()
b = a.factory()
c = a.factory()

b.compare(c)
print(id(b.__class__))
print(id(c.__class__))