TypeError:__class__赋值仅支持堆类型或ModuleType子类

时间:2018-04-08 14:06:18

标签: python setattr

我试图从任意基地复制功能'进入我的新对象。但是,我在此示例代码中收到以下错误。

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

如果在定义上述内容后将其输入提示符,则该语句有效。

3 个答案:

答案 0 :(得分:5)

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

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

由于调用类是如何创建该类的实例的,因此他们将被视为callables并通过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))]

或者你可以过滤掉课程:

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

答案 1 :(得分:3)

您的实例对象有许多不应重新分配的属性,并且大多数属性都通过了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__和朋友做些什么。也许在白名单之后检查下划线?

答案 2 :(得分:1)

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

我只想要这些功能,以便以下工作:

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