gpt4 book ai didi

python - 我怎样才能强制子类有 __slots__?

转载 作者:太空宇宙 更新时间:2023-11-03 14:37:33 25 4
gpt4 key购买 nike

我有一节课 __slots__ :

class A:
__slots__ = ('foo',)

如果我创建一个子类而不指定__slots__,子类将有一个__dict__:

class B(A):
pass

print('__dict__' in dir(B)) # True

有什么方法可以防止 B 有一个 __dict__ 而不必设置 __slots__ = ()

最佳答案

@AKX的答案几乎是正确的。我认为 __prepare__ 和元类确实是很容易解决这个问题的方法。

简单回顾一下:

  • 如果类的命名空间在类主体执行后包含 __slots__ 键,则该类将使用 __slots__ 而不是 __dict__
  • 可以使用 __prepare__ 将名称注入(inject)到类的命名空间之前

因此,如果我们简单地从 __prepare__ 返回包含键 '__slots__' 的字典,那么类将(如果 '__slots__' 键在类主体的评估期间不会再次删除)使用 __slots__ 而不是 __dict__。因为 __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__ 和将 __dict__ 添加到 __slots__ 之间是有区别的:

There's a minor difference between the two options: del __slots__ will give your class not only a __dict__, but also a __weakref__ slot.

关于python - 我怎样才能强制子类有 __slots__?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56579348/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com