所以,我正在阅读Python中的元类,以及type()
的三参数alter-ego如何用于动态创建类。但是,第三个参数通常是dict
,用于初始化要创建的类'__dict__
变量。
如果我想基于使用__slots__
而不是__dict__
的元类动态创建类,我该怎么做? type()
是否仍以某种方式使用以及覆盖__new__()
?
作为一个FYI,我知道__slots__
的正确用途,在创建大量类时节省内存而不是滥用它来强制执行类型安全。
设置__metaclass__
并使用__dict__
的普通(新式)类的示例:
class Meta(type):
def __new__(cls, name, bases, dctn):
# Do something unique ...
return type.__new__(cls, name, bases, dctn)
class Foo(object):
__metaclass__ = Meta
def __init__(self):
pass
在上文中,type.__new__()
被调用,第四个参数(实际使用后成为第三个参数)在__dict__
中创建Foo
。但是,如果我想修改Meta
以包含__slots__
,那么我没有字典可以传递给type()
的{{1}}函数(据我所知 - 我还没有测试任何这个,只是思考并试图找到某种用例场景。)
编辑:快速但未经测试的猜测是将值放入__new__()
变量并将其传递给__slots__
。然后将type.__new__()
添加到__init__()
,填充dict中的Meta
变量。虽然,我不确定该字典将如何到达__slots__
,因为__init__()
的声明会阻止创建__slots__
,除非在__dict__
中定义__dict__
。 ..
答案 0 :(得分:22)
您无法创建具有非空__slots__属性的类型。您可以做的是将__slots__属性插入到新类的dict中,如下所示:
class Meta(type):
def __new__(cls, name, bases, dctn):
dctn['__slots__'] = ( 'x', )
return type.__new__(cls, name, bases, dctn)
class Foo(object):
__metaclass__ = Meta
def __init__(self):
pass
现在Foo有了一些属性:
foo = Foo()
foo.y = 1
引发
AttributeError: 'Foo' object has no attribute 'y'
答案 1 :(得分:6)
dctn
是类字典,而不是实例字典。 __slots__
替换实例字典。如果您创建两个示例:
class Meta(type):
def __new__(cls, name, bases, dctn):
return type.__new__(cls, name, bases, dctn)
class Foo1(object):
__metaclass__ = Meta
class Foo2(object):
__metaclass__ = Meta
__slots__ = ['a', 'b']
然后:
>>> f1 = Foo1()
>>> f2 = Foo2()
>>> f1.__dict__ is Foo1.__dict__
False
>>> f2.__dict__
Traceback (most recent call last):
...
AttributeError: 'Foo2' object has no attribute '__dict__'
答案 2 :(得分:2)
如果type
的子类定义非空__slots__
,由于某些complicated implementation-related stuff,Python会抛出TypeError
。
In [1]:
class Meta(type):
__slots__ = ('x')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-38-1b16edef8eca> in <module>()
----> 1 class Meta(type):
2 __slots__ = ('x')
TypeError: nonempty __slots__ not supported for subtype of 'type'
另一方面,空__slots__
不会产生任何错误,但接缝无效。
In [2]:
class Meta(type):
__slots__ = ()
class Foo(metaclass=Meta):
pass
type(Foo)
Out [2]:
__main__.Meta
In [3]:
Foo.y = 42
Foo.y
Out [3]:
42
In [4]:
Foo.__dict__
Out [4]:
mappingproxy({'y': 42, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__module__': '__main__'})
In [5]:
foo = Meta('foo', (), {})
type(foo).__slots__
Out [5]:
()
In [6]:
foo.x = 42
foo.x
Out [6]:
42
In [7]:
foo.__dict__
Out [7]:
mappingproxy({'__dict__': <attribute '__dict__' of 'foo' objects>, 'x': 42, '__module__': '__main__', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'foo' objects>})
In [8]:
# Testing on non-metaclasses. Just in case.
class Bar:
__slots__ = ()
b = Bar()
b.__dict__
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-54-843730c66f3f> in <module>()
3
4 b = Bar()
----> 5 b.__dict__
AttributeError: 'Bar' object has no attribute '__dict__'