使用属性以Python格式限制属性访问

时间:2012-07-06 09:30:33

标签: coding-style attributes python

我正在尝试编写一个短类来表示存储在远程服务器上的对象。我希望在没有在远程服务器上设置对象的情况下在本地设置对象属性通常是个坏主意;它意味着本地对象不再代表远程对象,甚至没有意识到这一点。

我曾计划使用如下代码来处理这个问题。如果你想设置item.name,它可以让你自己用脚射击,但假设用户是明智的而不是这样做。

class Item(object):
    def __init__(self):
        self.name = get_item_name()

    def set_name(self, name):
        try:
            set_item_name(name)
        except:
            handle_error()
            raise
        else:
            self.name = name

但是,我最近遇到了@property装饰器,让我写下面的内容:

class Item(object):
    def __init__(self):
        self._name = get_item_name()

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        try:
            set_item_name(value)
        except:
            handle_error()
            raise
        else:
            self._name = value

这样做的好处是仍允许使用item.name进行属性访问,还可以处理item.name = blah分配。

然而,虽然第二个代码块提供了(在我看来似乎更好的)更好的行为,但它在属性设置中隐藏了一个函数调用,并且给出了 Zen 的“显式优于隐含的“以及Python类不应该向用户隐藏内容的一般想法,这是否会使第二块代码更少Pythonic?

1 个答案:

答案 0 :(得分:3)

用OO语言编写代码就是隐藏事物。当您编写方法doSomethingComplex()时,您基本上使用应用程序的语言创建一个新单词,该单词隐藏了必须使用该方法的开发人员的一些复杂操作。

虽然显式通常比隐式更好,但并不意味着总是。在您的情况下,问题不在于将方法调用隐藏在setter中,而在于您隐藏了网络。一旦您尝试从方法的用户隐藏真实的物理网络,您需要确保正确处理以下情况:

  1. 远方突然死亡
  2. 网络丢弃数据包(本地超时)
  3. 远程端抛出一个异常(你必须以某种方式将它带到本地代码,但它可能在本地没有意义)
  4. 远程端成功处理了呼叫但网络丢弃了答案(所以你确实成功但你不知道)
  5. 无论你怎么努力,这种隐藏的复杂性都会泄漏。举个简单的例子,使用此代码的开发人员必须处理网络异常和超时(与任何其他方法相反)。

    所以这里的休息时间少于你在setter中调用方法,但是你引入了一个全新的合约。

    什么是更好的解决方案?使网络呼叫显式。这意味着对代码用户的更明显的努力,但他们总是知道他们正在反对什么(而不是想知道为什么这个setter行为如此奇怪)。

    建议的实现:使用命令模式修改这些对象的状态。该命令需要修改对象的ID(因此您不 保留本地副本),要更改的字段和新值。

    远程端回复“成功”时更新本地缓存副本。如果远程端返回错误,请删除缓存的副本,以便再次获取它。

    这将创建更多代码,但这段代码非常简单明了。当您尝试隐藏远程端时,您将获得更少的代码,但它会更复杂和模糊。

    PS:永远不要认为人们在很长一段时间内都是明智的。