Python 只读包装器 class 拒绝访问某些方法和所有属性
Python read-only wrapper class that denies access to certain methods and all attributes
我有以下基础class。
class BaseWithMethod:
def __init__(self, prop=None):
self.prop = prop
def evil_method(self):
print(f"%@#&ç? {self.prop}")
我想创建一个包装器 class ReadonlyWrapperSelectedMethods
,它显示与基础 class 相同的功能,但不允许某些方法(本例中为 evil_method
)被称为。此外,包装实例应该是只读的,正如我在另一个 SO 问题 here 中所讨论的那样。这意味着一旦实例初始化,对 __setattr__
的调用应该引发错误。以下代码演示了该行为:
# Instantiate the wrapper class
readonly_instance = ReadonlyWrapperSelectedMethods()
# I can access properties
prop = readonly_instance.prop
# This should raise a PermissionError
readonly_instance.prop = 23
# This should also raise a PermissionError
readonly_instance.evil_method()
有没有办法在不修改基础class的情况下实现这种行为?请参阅下文,当基础 class 可能更改时如何完成。
尝试 1:修改基数 class
到目前为止,我已经尝试了以下方法。我在基础 class 中添加了一个属性 _initialized
并在 __init__
:
末尾将其设置为 True
class BaseWithMethodModified:
_initialized = False
def __init__(self, prop=None):
self.prop = prop
self._initialized = True
def evil_method(self):
print(f"%@#&ç? {self.prop}")
在这种情况下,下面的包装器 class 应该可以完成这项工作。它覆盖 __getattribute__
方法并将调用委托给超级 class.
允许的方法
class ReadonlyWrapperSelectedMethods(BaseWithMethodModified):
"""Read-only wrapper class."""
def __getattribute__(self, name: str):
if "evil" in name:
raise PermissionError()
else:
return super().__getattribute__(name)
def __setattr__(self, key, value) -> None:
if self.__getattribute__("_initialized"):
raise PermissionError()
else:
super().__setattr__(key, value)
这次尝试的问题是我不想修改基础class并且如果属性_initialized
在包装器class,它无法访问,因为所有属性访问都委托给基 class 到 __getattribute__
。也许这可以通过某种方式规避?
不要使用继承,使用组合。利用 __slots__
:
class Foo:
def __init__(self, prop=None):
self.prop = prop
def evil_method(self):
print(f"%@#&ç? {self.prop}")
class ReadOnlyWrapper:
__slots__ = ('_foo',)
def __init__(self, foo: Foo):
self._foo = foo
def __getattr__(self, name: str):
if "evil" in name:
raise PermissionError()
else:
return getattr(self._foo, name)
wrapper = ReadOnlyWrapper(Foo())
您可以简单地覆盖 __init__
方法:
class ReadonlyWrapperSelectedMethods(BaseWithMethod):
"""Read-only wrapper class."""
def __init__(self, prop=None):
super().__init__(prop)
self._initialized = True
def __getattribute__(self, name: str):
if "evil" in name:
raise PermissionError()
else:
return super().__getattribute__(name)
def __setattr__(self, key, value) -> None:
if hasattr(self, "_initialized"):
raise PermissionError()
else:
super().__setattr__(key, value)
在__init__
returns之后,对象是只读的:
>>> readonly_instance = ReadonlyWrapperSelectedMethods()
>>> vars(readonly_instance)
{'prop': None, '_initialized': True}
>>> prop = readonly_instance.prop
>>> readonly_instance.prop = 23
Traceback (most recent call last):
File "<pyshell#126>", line 1, in <module>
readonly_instance.prop = 23
File "<pyshell#121>", line 16, in __setattr__
raise PermissionError()
PermissionError
>>> readonly_instance.evil_method()
Traceback (most recent call last):
File "<pyshell#127>", line 1, in <module>
readonly_instance.evil_method()
File "<pyshell#121>", line 10, in __getattribute__
raise PermissionError()
PermissionError
我有以下基础class。
class BaseWithMethod:
def __init__(self, prop=None):
self.prop = prop
def evil_method(self):
print(f"%@#&ç? {self.prop}")
我想创建一个包装器 class ReadonlyWrapperSelectedMethods
,它显示与基础 class 相同的功能,但不允许某些方法(本例中为 evil_method
)被称为。此外,包装实例应该是只读的,正如我在另一个 SO 问题 here 中所讨论的那样。这意味着一旦实例初始化,对 __setattr__
的调用应该引发错误。以下代码演示了该行为:
# Instantiate the wrapper class
readonly_instance = ReadonlyWrapperSelectedMethods()
# I can access properties
prop = readonly_instance.prop
# This should raise a PermissionError
readonly_instance.prop = 23
# This should also raise a PermissionError
readonly_instance.evil_method()
有没有办法在不修改基础class的情况下实现这种行为?请参阅下文,当基础 class 可能更改时如何完成。
尝试 1:修改基数 class
到目前为止,我已经尝试了以下方法。我在基础 class 中添加了一个属性 _initialized
并在 __init__
:
True
class BaseWithMethodModified:
_initialized = False
def __init__(self, prop=None):
self.prop = prop
self._initialized = True
def evil_method(self):
print(f"%@#&ç? {self.prop}")
在这种情况下,下面的包装器 class 应该可以完成这项工作。它覆盖 __getattribute__
方法并将调用委托给超级 class.
class ReadonlyWrapperSelectedMethods(BaseWithMethodModified):
"""Read-only wrapper class."""
def __getattribute__(self, name: str):
if "evil" in name:
raise PermissionError()
else:
return super().__getattribute__(name)
def __setattr__(self, key, value) -> None:
if self.__getattribute__("_initialized"):
raise PermissionError()
else:
super().__setattr__(key, value)
这次尝试的问题是我不想修改基础class并且如果属性_initialized
在包装器class,它无法访问,因为所有属性访问都委托给基 class 到 __getattribute__
。也许这可以通过某种方式规避?
不要使用继承,使用组合。利用 __slots__
:
class Foo:
def __init__(self, prop=None):
self.prop = prop
def evil_method(self):
print(f"%@#&ç? {self.prop}")
class ReadOnlyWrapper:
__slots__ = ('_foo',)
def __init__(self, foo: Foo):
self._foo = foo
def __getattr__(self, name: str):
if "evil" in name:
raise PermissionError()
else:
return getattr(self._foo, name)
wrapper = ReadOnlyWrapper(Foo())
您可以简单地覆盖 __init__
方法:
class ReadonlyWrapperSelectedMethods(BaseWithMethod):
"""Read-only wrapper class."""
def __init__(self, prop=None):
super().__init__(prop)
self._initialized = True
def __getattribute__(self, name: str):
if "evil" in name:
raise PermissionError()
else:
return super().__getattribute__(name)
def __setattr__(self, key, value) -> None:
if hasattr(self, "_initialized"):
raise PermissionError()
else:
super().__setattr__(key, value)
在__init__
returns之后,对象是只读的:
>>> readonly_instance = ReadonlyWrapperSelectedMethods()
>>> vars(readonly_instance)
{'prop': None, '_initialized': True}
>>> prop = readonly_instance.prop
>>> readonly_instance.prop = 23
Traceback (most recent call last):
File "<pyshell#126>", line 1, in <module>
readonly_instance.prop = 23
File "<pyshell#121>", line 16, in __setattr__
raise PermissionError()
PermissionError
>>> readonly_instance.evil_method()
Traceback (most recent call last):
File "<pyshell#127>", line 1, in <module>
readonly_instance.evil_method()
File "<pyshell#121>", line 10, in __getattribute__
raise PermissionError()
PermissionError