如何像内置 classes 一样在 pre __init__ 状态下为 class 禁用 settattr?
How to disable settattr for your class in pre __init__ state just like build-in classes do?
因此,如果我在初始化之前使用内置列表尝试类似的操作:
list.hack = 'impossible'
我收到类型错误。
TypeError: can't set attributes of built-in/extension type 'list'
但是如果我像这样扩展内置列表 class:
class mylist(list):
def __setattr__(self, name, value):
raise NotImplementedError
我可以奇怪地做到这一点:
mylist.hack = 'haha'
当我初始化 "mylist" 时,我会在其中包含一个 "hack" 属性。
x = mylist()
x.hack
[Out]: 'haha'
尽管我在初始化后无法设置任何新属性 "mylist",但我可以在预初始化状态下设置。
是否可以使用自定义 classes 获得与内置函数相同的预初始化行为?
首先,__setattr__
def 不是必需的:
>>> class MyList(list):
... pass
>>> MyList.hack = 'haha'
>>> x = MyList()
>>> x.hack
'haha'
您不是将属性添加到实例 (x
),而是添加到 class (MyList
)。 (有些语言有一个 static
关键字来表示这些
属性(C++、Java、PHP、...)
大致相当于:
>>> class MyList(list):
... hack = 'haha' # class attribute, ie. "static"
>>> x = MyList()
>>> x.hack
'haha'
注意这与pre/post init:
无关
>>> class MyList(list):
... hack = 'haha'
>>> x = MyList()
>>> MyList.hack2 = 'hehe' # post init
你有:
>>> x.hack
'haha'
还有:
>>> x.hack2
'hehe'
总而言之,在 Python 中:
- 可以在class定义后添加class属性;
- 如果
x
是 C
的一个实例并且 attr
是 C
的一个属性,那么 x.attr
等价于 C.attr
。
郑重声明,您可以使用 metaclass:
来防止这种灵活的行为
>>> 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
备注:
- 除非您知道自己在做什么,否则不要这样做。
- 不要使用它来保护您的 classes:可以轻松绕过此行为并添加 class 属性。
言论总结:不要这样做.
因此,如果我在初始化之前使用内置列表尝试类似的操作:
list.hack = 'impossible'
我收到类型错误。
TypeError: can't set attributes of built-in/extension type 'list'
但是如果我像这样扩展内置列表 class:
class mylist(list):
def __setattr__(self, name, value):
raise NotImplementedError
我可以奇怪地做到这一点:
mylist.hack = 'haha'
当我初始化 "mylist" 时,我会在其中包含一个 "hack" 属性。
x = mylist()
x.hack
[Out]: 'haha'
尽管我在初始化后无法设置任何新属性 "mylist",但我可以在预初始化状态下设置。
是否可以使用自定义 classes 获得与内置函数相同的预初始化行为?
首先,__setattr__
def 不是必需的:
>>> class MyList(list):
... pass
>>> MyList.hack = 'haha'
>>> x = MyList()
>>> x.hack
'haha'
您不是将属性添加到实例 (x
),而是添加到 class (MyList
)。 (有些语言有一个 static
关键字来表示这些
属性(C++、Java、PHP、...)
大致相当于:
>>> class MyList(list):
... hack = 'haha' # class attribute, ie. "static"
>>> x = MyList()
>>> x.hack
'haha'
注意这与pre/post init:
无关>>> class MyList(list):
... hack = 'haha'
>>> x = MyList()
>>> MyList.hack2 = 'hehe' # post init
你有:
>>> x.hack
'haha'
还有:
>>> x.hack2
'hehe'
总而言之,在 Python 中:
- 可以在class定义后添加class属性;
- 如果
x
是C
的一个实例并且attr
是C
的一个属性,那么x.attr
等价于C.attr
。
郑重声明,您可以使用 metaclass:
来防止这种灵活的行为>>> 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
备注:
- 除非您知道自己在做什么,否则不要这样做。
- 不要使用它来保护您的 classes:可以轻松绕过此行为并添加 class 属性。
言论总结:不要这样做.