TypeError: __class__ assignment only supported for heap types or ModuleType subclasses

TypeError: __class__ assignment only supported for heap types or ModuleType subclasses

我正在尝试将函数从任意 'base' class 复制到我的新对象中。但是,此示例代码出现以下错误。

class my_base:
    def print_hey():
        print("HEY")

    def get_one():
        print(1)

class my_ext:
    def __init__(self, base):
        methods = [method for method in dir(base) if callable(getattr(base, method))]
        for method in methods:
            setattr(self, method, getattr(base, method))


me = my_ext(my_base)
me.get_one()

以上调用 setattr.

时出现此错误
 TypeError: __class__ assignment only supported for heap types or ModuleType subclasses

如果我在定义上面的内容后在提示符中键入该语句,该语句就有效。

您的实例对象有许多不应重新分配的属性,其中大部分都通过了 callable 测试:

>>> [item for item in dir(my_base) if callable(getattr(my_base, item))]
['__class__', '__delattr__', '__dir__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'get_one', 'print_hey']

你应该限制其中的大部分。您可以简单地检查 item.startswith('__'),但我不确定您想对 __repr__ 和朋友做什么。也许在白名单后检查下划线?

事实证明 __class__ 是可调用的,并且还有许多其他可调用的。

我只想要功能,所以下面的工作:

 import types
 . . . 
  methods = [method for method in dir(base) if isinstance(getattr(base, method), types.FunctionType)]
 . . .

这里的问题是 python 中的所有对象都有一个存储对象类型的 __class__ 属性:

>>> my_base.__class__
<class 'type'>
>>> type(my_base)
<class 'type'>

由于调用 class 是创建 class 实例的方式,因此它们被视为可调用对象并通过了 callable 测试:

>>> callable(my_base)
True
>>> my_base()
<__main__.my_base object at 0x7f2ea5304208>

并且当您的代码尝试将某些内容分配给 __class__ 属性时,您观察到的 TypeError 被抛出:

>>> object().__class__ = int
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ assignment only supported for heap types or ModuleType subclasses

因此您需要更具体地说明应复制哪些属性。

您可以过滤掉带有双下划线的属性:

methods = [method for method in dir(base) if not method.startswith('__')
                                             and callable(getattr(base, method))]

或者您可以过滤掉 classes:

methods = [method for method in dir(base) if callable(getattr(base, method)) and
                                     not isinstance(getattr(base, method), type)]

或者您只能通过比较 types.FunctionType:

来允许函数
methods = [method for method in dir(base) if callable(getattr(base, method)) and
                           isinstance(getattr(base, method), types.FunctionType)]