拒绝访问某些方法和所有属性的 Python 只读包装类 尝试一:修改基类

问题描述

我有以下基类。

class BaseWithMethod:
    def __init__(self,prop=None):
        self.prop = prop

    def evil_method(self):
        print(f"%@#&ç? {self.prop}")

我想创建一个包装类 ReadonlyWrapperSelectedMethods,它显示与基类相同的功能,但不允许调用某些方法(在此示例中为 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()

有没有办法在不修改基类的情况下实现这种行为?当基类可能发生变化时,请参阅下文。

尝试一:修改基类

到目前为止,我已经尝试了以下方法。我向基类添加一个属性 _initialized,并在 True 的末尾将其设置为 __init__

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__ 委托给基类。也许这可以通过某种方式规避?

解决方法

不要使用继承,使用组合。利用__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__ 返回后,对象为只读:

>>> 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>",in <module>
    readonly_instance.evil_method()
  File "<pyshell#121>",line 10,in __getattribute__
    raise PermissionError()
PermissionError

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...