1

python中有没有一种方法可以给定一个python类:

class Foo(object):
    apple = None
    orange = None
    def __init__(self, apple=None, orange=None)
        super(Foo, self).__init__()
        self.apple = apple
        self.orange = orange

在 Foo 对象为init之后,必须始终将两个属性之一(apple、orange)分配给 None 以外的值,并且任何时候都不应将这两个属性分配给 None 以外的值。

换句话说:

                      orange is None    |    orange is not None
                                        |
apple is None              NO           |         YES                                         
________________________________________|___________________________
                                        |
apple is not None          YES          |         NO

在python中如何做到这一点?

4

6 回答 6

4

在构造函数中,如果它们都设置了或都设置raise了,这很简单。问题稍后在代码中。ValueErrorNone

遵循最不意外的原则,我认为您应该将变量标记为私有并使用 setter 方法(不是属性 setter,普通的旧方法)。这清楚地表明您在设置值时正在执行额外的逻辑,并且它为您提供了一个明显的位置,以便稍后在需要时添加额外的逻辑。不过,使用 getter 属性方法会很好。所以是这样的:

class Foo(object):
    def __init__(self, apple=None, orange=None):
        super(Foo, self).__init__()
        if apple is None and orange is None:
            raise ValueError('apple and orange cannot both be None')
        if apple is not None and orange is not None:
            raise ValueError('apple and orange cannot both be set')

        self._apple = apple
        self._orange = orange

    @property
    def apple(self):
        return self._apple

    @property
    def orange(self):
        return self._orange

    def setAppleClearOrange(self, value):
        if value is None:
            raise ValueError('Cannot set both to None')
        self._orange = None
        self._apple = value

    def setOrangeClearApple(self, value):
        if value is None:
            raise ValueError('Cannot set both to None')
        self._apple = None
        self._orange = value

是的,它有点冗长,但很明显你的意图是什么,这实际上更重要。

于 2013-05-29T04:55:03.903 回答
1

就像是

if !((self.apple==None)^(self.orange==None))
    // some error

可能会成功... ^ 是 XOR 运算符,如果其中一个(但不是两个)操作数为真,则返回真。

于 2013-05-29T04:51:54.097 回答
0
objs = filter(None, [apple, orange, ...])
if len(objs) == 0:
   raise Exception("At least 1 object of [apple, orange] must be different from None.") 
elif len(objs) > 1:
    raise Exception("At most 1 object of [apple, orange] should be different from None.")
于 2013-05-29T04:52:56.133 回答
0

您可以覆盖__setattr__()该类,并让它为您处理该逻辑。请参阅http://docs.python.org/2/reference/datamodel.html#object。设置

就像是

class FooBar(object):
    def __setattr__(self, key, val):
        if key == 'apple' or key == 'orange':
            # Decide what to do about it
        self.__dict__[key] = val

请注意,您需要通过对象访问密钥__dict__以避免无限循环,因为它__setattr__() 取代了正常的分配机制。

另外,请注意,这将检查对这两个变量的每个分配,包括在您自己的代码中。如果这不是您想要的__init__(),请按照其他人的建议进行一些测试。

于 2013-05-29T04:54:17.967 回答
0

None这是一个版本,如有必要,将设置另一个方面。如果它们都设置为,您必须定义会发生什么None

class Foo(object):
    def __init__(self, apple=None, orange=None):
        # make sure exactly 1 of apple/orange is not None
        if sum(x is None for x in (apple, orange)) != 1:
            raise ...
        self._apple = apple
        self._orange = orange

    @property
    def apple(self):
        return self._apple

    @apple.setter
    def apple(self, value):
        if value is not None:
            self._orange = None
        elif self._orange is None:
            raise ...
        self._apple = value

    @property
    def orange(self):
        return self._orange

    @orange.setter
    def orange(self, value):
        if value is not None:
            self._apple = None
        elif self._apple is None:
            raise ...
        self._orange = value
于 2013-05-29T04:59:17.517 回答
0
assert (apple is None) != (orange is None)

如果您将该代码放在 __init__ 方法中,并且您的前提条件为假,AssertionError则会抛出 an 。

于 2013-05-29T05:04:11.860 回答