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

Classes returned from class factory have different IDs

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

有没有简单的方法可以做到这一点?我知道这并不完全符合鸭子类型,但这是我正在编写的程序的最简单解决方案。

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))

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

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

这是因为它们实际上是不同的 类,在调用时是动态创建的并且在局部范围内。

解决此问题的一种方法是 return(或 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])

你问的不是很清楚。在我看来你想要一个你已经发布的代码的更简单版本。如果那不正确,则此答案不相关。

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

def compare(self, other):
        ...

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

type 接受三个参数:名称、父级和预定义槽。所以这将与您之前的代码的行为方式相同。

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

从@rassar 的回答中,我意识到 class 每次都是动态创建的,因此在父对象(甚至在父对象之上)中定义它,意味着它将是相同的 class每次调用时定义。

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__))

如果您的 class 定义在工厂函数内部,那么您创建的 class 的每个实例都将是 一个单独的 class。那是因为 class 定义是一个语句,它的执行就像任何其他赋值一样。不同class的名称和内容会相同,但身份不同。

我认为没有任何简单的方法可以在不以某种方式更改代码结构的情况下解决这个问题。您已经说过您的实际工厂函数是 class 的方法,这表明您可以将 class 定义移动到其他地方,以便它可以由对工厂的多次调用共享方法。根据您希望内部 class 从外部 class 使用什么信息,您可以在 class 级别定义它(因此只使用一个 class 定义无处不在),或者您可以用另一种方法定义它,例如 __init__(这将为外部 class 的每个实例创建一个新的内部 class)。

最后一种方法可能如下所示:

class Outer(object):
    def __init__(self):
        class Inner(object):
            def compare(self, other):
                print('Comparison Result: {}'.format(isinstance(other, self.__class__)))
        self.Inner = Inner

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

f = Outer()
a = f.factory()
b = f.factory()
print(a.compare(b)) # True

g = Outer() # create another instance of the outer class
c = g.factory()
print(a.compare(c)) # False