我有一个__slots__的类
class A:
__slots__ = ('foo',)如果我创建一个子类而不指定__slots__,则子类将具有一个__dict__
class B(A):
pass
print('__dict__' in dir(B)) # True有什么方法可以防止B在不需要设置__slots__ = ()的情况下拥有__dict__
发布于 2019-06-13 16:06:48
@AKX的答案几乎是正确的。我认为__prepare__和元类确实是很容易解决的方法。
我只是简单地回顾一下:
__slots__键,那么类将使用__slots__而不是__dict__。__prepare__执行类主体之前,可以将名称注入类的命名空间。因此,如果我们只返回一个字典,其中包含来自'__slots__'的键,那么类将使用__slots__而不是__dict__ (如果'__slots__'键在类主体的计算过程中不再被移除)。因为__prepare__只是提供了初始的命名空间,所以可以轻松地覆盖__slots__,或者在类主体中再次删除它们。
因此,默认情况下提供__slots__的元类如下所示:
class ForceSlots(type):
@classmethod
def __prepare__(metaclass, name, bases, **kwds):
# calling super is not strictly necessary because
# type.__prepare() simply returns an empty dict.
# But if you plan to use metaclass-mixins then this is essential!
super_prepared = super().__prepare__(metaclass, name, bases, **kwds)
super_prepared['__slots__'] = ()
return super_prepared因此,每个具有这个元类的类和子类(默认情况下)名称空间中都有一个空的__slots__,因此创建了一个“带槽的类”(除非__slots__是有意删除的)。
为了说明它是如何工作的:
class A(metaclass=ForceSlots):
__slots__ = "a",
class B(A): # no __dict__ even if slots are not defined explicitly
pass
class C(A): # no __dict__, but provides additional __slots__
__slots__ = "c",
class D(A): # creates normal __dict__-based class because __slots__ was removed
del __slots__
class E(A): # has a __dict__ because we added it to __slots__
__slots__ = "__dict__",它通过了AKZ答复中提到的测试:
assert "__dict__" not in dir(A)
assert "__dict__" not in dir(B)
assert "__dict__" not in dir(C)
assert "__dict__" in dir(D)
assert "__dict__" in dir(E)并核实它是否如预期的那样工作:
# A has slots from A: a
a = A()
a.a = 1
a.b = 1 # AttributeError: 'A' object has no attribute 'b'
# B has slots from A: a
b = B()
b.a = 1
b.b = 1 # AttributeError: 'B' object has no attribute 'b'
# C has the slots from A and C: a and c
c = C()
c.a = 1
c.b = 1 # AttributeError: 'C' object has no attribute 'b'
c.c = 1
# D has a dict and allows any attribute name
d = D()
d.a = 1
d.b = 1
d.c = 1
# E has a dict and allows any attribute name
e = E()
e.a = 1
e.b = 1
e.c = 1正如在注释( Aran-Fey)中指出的,del __slots__和向__slots__添加__dict__之间有一个区别
这两个选项之间有一个细微的区别:
del __slots__不仅会给您的类提供一个__dict__,而且还会给您的类提供一个__weakref__插槽。
发布于 2019-06-13 12:09:48
像这样的元类和 hook怎么样?
import sys
class InheritSlots(type):
def __prepare__(name, bases, **kwds):
# this could combine slots from bases, I guess, and walk the base hierarchy, etc
for base in bases:
if base.__slots__:
kwds["__slots__"] = base.__slots__
break
return kwds
class A(metaclass=InheritSlots):
__slots__ = ("foo", "bar", "quux")
class B(A):
pass
assert A.__slots__
assert B.__slots__ == A.__slots__
assert "__dict__" not in dir(A)
assert "__dict__" not in dir(B)
print(sys.getsizeof(A()))
print(sys.getsizeof(B()))由于某些原因,这仍然打印64, 88 -也许继承的类的实例总是比基类本身重一点?
https://stackoverflow.com/questions/56579348
复制相似问题