设置属性时抛出错误

时间:2017-11-01 06:09:27

标签: python

我有一个属性deleted的类。用户必须使用ob.delete()方法。如果他试图直接做ob.deleted = True,他应该会收到错误。

class A(ORMBaseClass):
    deleted = False

    def delete(self):
        self.deleted = True


a = A()
a.delete() # works
print(a.delete) # works
a.deleted = True # must throw exception
Exception: you cannot directly set deleted

我尝试重载__setattr__,但同样会影响ob.delete()

具有ob._deleted私有属性和ob.deleted属性的属性不适合,因为该类是ORM模型,并且他面临session.query(A).filter(A._deleted == True)a.deleted=True的UX不一致。 / p>

我知道Python没有完全安全的方法,我只想停下来并通知用户设置它。

3 个答案:

答案 0 :(得分:2)

这样的事情应该有效:

class A(object):
    def __init__(self):
        self._deleted = False

    @property
    def deleted(self):
        return self._deleted

    @deleted.setter
    def deleted(self, value):
        raise Exception("Can't directly set deleted")

    def delete(self):
        self._deleted = True

指定属性的get和set方法,如果直接调用setter,则引发异常。这将适用于Python 2.7和3.x。

答案 1 :(得分:2)

可以这样做:

def __setattr__(self, name, value):
    if name == 'deleted':
        raise AttributeError("you cannot directly set deleted")
    object.__setattr__(self, name, value)

然后,在delete中,您必须直接致电object.__setattr__(self, 'deleted', True)来解决这个问题。

但你可能不应该真的这样做。如果您希望成员变量为" private",只需将其名称以下划线开头,例如_deleted。它仍然是可写的,但它是一种惯例,意味着"变量是私有的,不要碰它"。

答案 2 :(得分:0)

在我看来,这是一个更好的解决方案,它是以前解决方案的混合。

你可以为私人成员使用python技术(名称修改)

class A(ORMBaseClass):
    __deleted = False

    def delete(self):
        self.__deleted = True

    @property
    def deleted(self):
        return self.__deleted

首先注意,该成员使用两个下划线将变量设为私有。使用两个下划线不仅仅是像提议的1下划线那样的约定。它将使python在属性上使用名称修改。在这种情况下,访问此属性的唯一方法是通过obj._A__deleted它仍然可写,但它比使用一个下划线要好得多。

现在您有一个将__deleted设置为True的简单方法以及一个返回值的属性。这里没什么复杂的。

为什么名称重整很重要?

如果您在此处执行此操作:

class B(A):
    __deleted = True

    @property
    def deleted2(self):
        return self.__deleted

猜猜什么是返回值:

obj = B()
obj.deleted 

如果你猜到了False那么你就对了!类B将定义名为_B__deleted的属性,而类A _A__deleted。正如您所看到的,名称修改阻止子类从上层类中意外地访问属性。当您尝试从类外的任何位置访问__deleted时,属性将是未定义的......

理论上,如果你想拥有真正的私有,你可以使用一个元类,每次构造一个类时,它将使用随机名称构造类似的东西。