【问题标题】:Prohibit class member from being set to None in Python禁止在 Python 中将类成员设置为 None
【发布时间】:2020-07-31 12:17:37
【问题描述】:

在 Python 中是否有办法禁止在 __init__ 之外将类成员设置为 None?

class Dummy:
    def __init__(self, x):
        if x is not None:
            self.x = x
        else:
            raise Exception("x cannot be None")

d = Dummy("foo")
d.x = None

在我的代码中,我有类型提示,但没有强制执行,所以说 x 只能是 str 并没有真正改变任何允许的内容。

【问题讨论】:

标签: python


【解决方案1】:

你需要一个@property:

class Dummy:
    def __init__(self, x):
        self.x = x

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        if value is None:
            raise Exception("x cannot be None")
        self._x = value


d = Dummy(8)
d.x = 16
d.x = None  # Raises

【讨论】:

  • 重要的是要指出(不幸的是)这不会阻止某人(如果他们真的坚持不懈)做d._x = None
  • _init中,应该是self._x
  • @Rashid'Lee'Ibrahim 不,不是。否则Dummy(None) 将起作用
  • @DeepSpace 确实如此,但一般来说,一旦您从外部触摸带下划线前缀的变量,所有保证和保证往往都无效:-)
  • @MaxPower 您可以使用__x 来获得更混乱的名称,但是不,没有什么可以阻止真正持久的误用用户。
【解决方案2】:

注意:我将这里的问题解释为防止 所有 属性在 __init__ 之外设置为 None,尽管在下面添加了一个选项来保护某些指定的属性。

这个怎么样?将__setattr__ 方法作为object.__setattr__ 的包装器。

class Dummy:
    def __init__(self, x):
        self._None_forbidden = False
        self.z = None  # this will work
        self._None_forbidden = True

    def __setattr__(self, k, v):
        if v is None and self._None_forbidden:
            raise ValueError("cannot set attribute to None")
        object.__setattr__(self, k, v)


d = Dummy("foo")
print(d.z)  # None
d.y = 2
print(d.y)  # 2
d.x = None  # raises ValueError

如果您只是想保护某些属性,您可以将self._None_forbidden 设置为一组不允许设置为 None 的属性名称。例如:

class Dummy:
    def __init__(self, x):
        self._None_forbidden = set()
        self.z = None  # this will work
        self._None_forbidden.add("z")

    def __setattr__(self, k, v):
        if v is None and k in self._None_forbidden:
            raise ValueError("cannot set attribute to None")
        object.__setattr__(self, k, v)


d = Dummy("foo")
print(d.z)  # None
d.y = 2
print(d.y)  # 2
d.x = None
print(d.x)  # None
d.z = 4
print(d.z)  # 4
d.z = None  # raises ValueError

显然,如果调用者操纵了_None_forbidden,那么这可以被规避,但他们应该知道他们正在做一些不受支持的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 2014-11-27
    • 2014-09-26
    相关资源
    最近更新 更多