我试图从任意基地复制功能'进入我的新对象。但是,我在此示例代码中收到以下错误。
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
如果在定义上述内容后将其输入提示符,则该语句有效。
答案 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)]
. . .