拒绝访问某些方法和所有属性的Python只读包装器类



我有以下基类。

class BaseWithMethod:
def __init__(self, prop=None):
self.prop = prop
def evil_method(self):
print(f"%@#&ç? {self.prop}")

我想创建一个包装类ReadonlyWrapperSelectedMethods,它显示与基类相同的功能,但不允许调用某些方法(本例中为evil_method(。此外,包装的实例应该是只读的,正如我在这里的另一个SO问题中所讨论的那样。这意味着一旦初始化实例,对__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()

有没有一种方法可以在不修改基类的情况下实现这种行为?请参阅下面如何在基类可能发生更改时执行此操作。

尝试1:修改基类

到目前为止,我已经尝试了以下内容。我向基类添加了一个属性_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}")

在这种情况下,下面的包装类应该完成这项工作。它重写__getattribute__方法,并将调用委托给允许超类使用的方法。

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)

这种尝试的问题是,我不想修改基类,如果属性_initialized是在包装类中定义的,则无法访问它,因为所有属性访问都是通过__getattribute__委派给基类的。也许这可以通过某种方式规避?

您可以简单地覆盖__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__返回后,对象为只读:

>>> 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

不要使用继承,要使用组合。利用__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())

最新更新