首先让我说我了解插槽和元类在 Python 中是如何工作的。玩弄这两个,我遇到了一个有趣的问题。这是一个最小的例子:
def decorator(cls):
dct = dict(cls.__dict__)
dct['__slots__'] = ('y',)
return type('NewClass', cls.__bases__, dct)
@decorator
class A(object):
__slots__= ('x',)
def __init__(self):
self.x = 'xx'
A()
这会产生以下异常:
Traceback (most recent call last):
File "p.py", line 12, in <module>
A()
File "p.py", line 10, in __init__
self.x = 'xx'
TypeError: descriptor 'x' for 'A' objects doesn't apply to 'NewClass' object
现在,我知道为什么会发生这种情况了:为插槽创建的描述符x
必须能够引用插槽的保留空间。只有 A 类的实例或 A 的子类的实例才有这个保留空间,因此只有那些实例才能使用描述符x
。在上面的例子中,元类创建了一个新类型,它是 A 的基类的子类,但不是 A 本身的子类,所以我们得到了异常。很简单。
当然,在这个简单的例子中,以下两个定义中的任一个decorator
都可以解决这个问题:
def decorator(cls):
dct = dict(cls.__dict__)
dct['__slots__'] = ('y',)
return type('NewClass', (cls,) + cls.__bases__, dct)
def decorator(cls):
class NewClass(cls):
__slots__ = ('y',)
return NewClass
但是这些变通办法与原来的不完全相同,因为它们都将 A 添加为基类。他们可能会在更复杂的设置中失败。例如,如果继承树更复杂,您可能会遇到以下异常:TypeError: multiple bases have instance lay-out conflict
.
所以我非常具体的问题是:
有没有办法通过调用来创建一个新类来type
修改__slots__
现有类的属性,但不将现有类添加为新类的基类?
编辑:
我知道对于我上面的示例,严格的元类是另一种解决方法。有很多方法可以使最小的示例起作用,但我的问题是关于通过new
基于现有类创建一个类,而不是关于如何使示例工作。对困惑感到抱歉。
编辑2:
评论中的讨论让我提出了一个比我最初提出的更精确的问题:
是否可以通过调用创建一个类,该类type
使用现有类的插槽和描述符,而不是该类的后代?
如果答案是“不”,我会很感激为什么不这样做的消息来源。