我有一个属性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没有完全安全的方法,我只想停下来并通知用户设置它。
答案 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
时,属性将是未定义的......
理论上,如果你想拥有真正的私有,你可以使用一个元类,每次构造一个类时,它将使用随机名称构造类似的东西。