我有一个类,它具有一些属性和更改这些属性的方法. (这是一个最小的例子)

class MyClass:
    def __init__(self) -> None:
        self.acting = False
        self.att1 = None
        self.att2 = None
        self.att3 = None

    def set_att1(self, value):
        self.att1 = value

    def set_att2(self, value):
        self.att2 = value

    def set_att3(self, value):
        self.att3 = value

    def switch_acting(self):
        self.acting = not self.acting
    

我想阻止使用在自身时更改某些属性的方法.action为True. 此块可能是引发的错误或错误返回.

我知道我可以只在每个方法的开头放一条if语句来判断自身,或者使用一个修饰符,但我想以一种自动的方式这样做,在这种方式下,它将阻止使用所有以"set"开头的函数,而不必向所有函数添加代码.

我怎么能这样做呢?

推荐答案

你可以在这里用__getattribute__,意思是:

In [1]: class MyClass:
   ...:     def __init__(self) -> None:
   ...:         self.acting = False
   ...:         self.att1 = None
   ...:         self.att2 = None
   ...:         self.att3 = None
   ...:
   ...:     def __getattribute__(self, attribute):
   ...:         if attribute.startswith("set_") and not self.acting:
   ...:             raise RuntimeError(f"{self} is not acting")
   ...:         return super().__getattribute__(attribute)
   ...:
   ...:     def set_att1(self, value):
   ...:         self.att1 = value
   ...:
   ...:     def set_att2(self, value):
   ...:         self.att2 = value
   ...:
   ...:     def set_att3(self, value):
   ...:         self.att3 = value
   ...:
   ...:     def switch_acting(self):
   ...:         self.acting = not self.acting
   ...:

In [2]: instance = MyClass()

In [3]: instance.set_att1(10)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-3-ead9d2b57142> in <module>
----> 1 instance.set_att1(10)

<ipython-input-1-585c5de84d26> in __getattribute__(self, attribute)
      8     def __getattribute__(self, attribute):
      9         if attribute.startswith("set_") and not self.acting:
---> 10             raise RuntimeError(f"{self} is not acting")
     11         return super().__getattribute__(attribute)
     12

RuntimeError: <__main__.MyClass object at 0x7f9a00520af0> is not acting

In [4]: instance.switch_acting()

In [5]: instance.set_att1(10)

In [6]: instance.att1
Out[6]: 10

但是,正如注释中所指出的,这将在查找属性时判断self.acting标志,而不一定是在调用方法时判断.

我们可以更仔细地处理验证应该在方法is called而不是被访问时发生的事实:

class MyClass:
    def __init__(self) -> None:
        self.acting = False
        self.att1 = None
        self.att2 = None
        self.att3 = None

    def __getattribute__(self, attribute):
        if attribute.startswith("set_"):
            bound_method  = super().__getattribute__(attribute).__get__(self, type(self))
            def _wrapper(*args, **kwargs):
                if not self.acting:
                    raise RuntimeError(f"{self} is not acting")
                return bound_method(*args, **kwargs)
            return _wrapper
        return super().__getattribute__(attribute)

    def set_att1(self, value):
        self.att1 = value

    def set_att2(self, value):
        self.att2 = value

    def set_att3(self, value):
        self.att3 = value

    def switch_acting(self):
        self.acting = not self.acting

演示:

In [29]: instance = MyClass()

In [30]: instance.set_att1(10)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-30-ead9d2b57142> in <module>
----> 1 instance.set_att1(10)

<ipython-input-28-53d1a32f1498> in _wrapper(*args, **kwargs)
     11             def _wrapper(*args, **kwargs):
     12                 if not self.acting:
---> 13                     raise RuntimeError(f"{self} is not acting")
     14                 return bound_method(*args, **kwargs)
     15             return _wrapper

RuntimeError: <__main__.MyClass object at 0x7f99e05bf340> is not acting

In [31]: instance.switch_acting()

In [32]: instance.set_att1(10)

In [33]: instance.att1
Out[33]: 10

In [34]: f = instance.set_att2

In [35]: instance.switch_acting()

In [36]: f(20)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-36-a5c3c0536773> in <module>
----> 1 f(20)

<ipython-input-28-53d1a32f1498> in _wrapper(*args, **kwargs)
     11             def _wrapper(*args, **kwargs):
     12                 if not self.acting:
---> 13                     raise RuntimeError(f"{self} is not acting")
     14                 return bound_method(*args, **kwargs)
     15             return _wrapper

RuntimeError: <__main__.MyClass object at 0x7f99e05bf340> is not acting

In [37]: instance.switch_acting()

In [38]: f(20)

In [39]: instance.att2
Out[39]: 20

编辑:我想我做的与你想要的相反,但同样的方法应该有效,只需勾选if self.acting而不是if not self.acting

Python相关问答推荐

判断两极中N(N 2)列水平是否相等

使用decorator 重复超载

按日期和组增量计算总价值

Django序列化器没有验证或保存数据

Python中的Pool.starmap异常处理

inspect_asm不给出输出

将numpy矩阵映射到字符串矩阵

实现的差异取决于计算出的表达是直接返回还是首先存储在变量中然后返回

GL pygame无法让缓冲区与vertextPointer和colorPointer一起可靠地工作

try 与gemini-pro进行多轮聊天时出错

替换字符串中的多个重叠子字符串

如何更改分组条形图中条形图的 colored颜色 ?

如何在solve()之后获得症状上的等式的值

SQLAlchemy Like ALL ORM analog

实现自定义QWidgets作为QTimeEdit的弹出窗口

Pandas—在数据透视表中占总数的百分比

无法在Docker内部运行Python的Matlab SDK模块,但本地没有问题

如何使regex代码只适用于空的目标单元格

如何使用使用来自其他列的值的公式更新一个rabrame列?

关于两个表达式的区别