如何像内置类一样在__init__之前的状态下为您的类禁用settattr?

问题描述 投票:0回答:1

因此,如果我在初始化之前尝试使用内置列表进行此类操作:

list.hack = 'impossible'

我收到TypeError。

TypeError: can't set attributes of built-in/extension type 'list'

但是如果我使我的类像这样扩展内置列表:

class mylist(list):
    def __setattr__(self, name, value):
        raise NotImplementedError

我可以奇怪地做到这一点:

mylist.hack = 'haha'

并且当我初始化“ mylist”时,我将在其中包含“ hack”属性。

x = mylist()
x.hack
[Out]: 'haha'

即使我在初始化“ mylist”之后无法设置任何新属性,也可以在初始化前的状态下进行设置。

自定义类是否有可能获得与内置类相同的预初始化行为?

python built-in mutability
1个回答
0
投票

首先,不需要__setattr__ def:

>>> class MyList(list):
...     pass

>>> MyList.hack = 'haha'
>>> x = MyList()
>>> x.hack
'haha'

您不是将属性添加到实例(x),而是添加到类(MyList)。 (对于某些语言,这些语言使用static关键字属性(C ++,Java,PHP等)。)

大致相当于:

>>> class MyList(list):
...     hack = 'haha' # class attribute, ie. "static"

>>> x = MyList()
>>> x.hack
'haha'

注意,这与之前/之后的初始化无关:

>>> class MyList(list):
...     hack = 'haha'

>>> x = MyList()
>>> MyList.hack2 = 'hehe' # post init

您有:

>>> x.hack
'haha'

而且:

>>> x.hack2
'hehe'

总结,在Python中:

  • 您可以在类定义之后添加类属性;
  • 如果xC的实例,并且attrC的属性,则x.attr等效于C.attr

为了记录,您可以使用元类防止这种灵活的行为:

>>> class MyListMeta(type):
...     def __setattr__(self, name, value):
...         raise AttributeError()

>>> class MyList(list, metaclass=MyListMeta):
...     hack = 'haha'

按预期:

>>> x = MyList()
>>> x.hack
'haha'

但是现在:

>>> MyList.hack2 = 'hehe'
Traceback (most recent call last):
...
AttributeError

注意,您也不能设置现有属性:

>>> MyList.hack = 'hehe'
Traceback (most recent call last):
...
AttributeError

备注:

  • 除非您知道自己在做什么,否则不要这样做。
  • 请勿使用此方法保护您的类:可以轻松绕过此行为并添加类属性。

评论摘要:不这样做

© www.soinside.com 2019 - 2024. All rights reserved.