【问题标题】:Defining Python class instance attributes定义 Python 类实例属性
【发布时间】:2018-06-12 15:50:03
【问题描述】:

给定一个允许 3 种可能输入的类定义:

class FooBar(object):
    def __init__(self, x=None, y=None, z=None):
        if x is not None:
            self.x = x
        elif if y is not None:
            self.y = y
        elif if z is not None:
            self.z = z
        else:
            raise ValueError('Please supply either x,y or z')

这 3 个输入是相互关联的,比如说:

x = .5*y = .25*z

这也意味着:

y = .5*z = 2*x

z = 2*y = 4*x

当创建FooBar() 的实例时,用户需要提供其中之一,__init__ 会处理它。

现在我想做以下事情

  • 如果 3 个变量中的任何一个发生变化,其他变量也会按照关系发生变化。

为了实现我所做的:

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

@x.setter
def x(self, value):
    self._x = value
    self._y = 2*self._x
    self._z = 4*self._x

还有其他人:

@property
def y(self):
    return self._y

@y.setter
def y(self, value):
    self._y = value
    self._x = .5*self._y
    self._z = 2*self._y

@property
def z(self):
    return self._z

@z.setter
def z(self, value):
    self._z = value
    self._x = .25*self._z
    self._y = .5*self._z

这是正确的方法吗?

【问题讨论】:

  • 如果我提供FooBar(x=1, y=1425)怎么办?
  • 如果x = 2*y,则self._y = value/2x 的设置器。不是value * 2
  • 基于我的__init__x优先,这就是和if elif...的原因。
  • 好的。我做了相反的事情,你是对的。但我更担心的是实例变量设置。

标签: python class properties getter-setter


【解决方案1】:

我认为你让这件事变得比你必须做的更复杂。如果变量是相关的,并且一个可以完全由另一个确定,则不需要存储三个变量。您可以存储一个变量,并动态计算其他变量。喜欢:

class Foo(object):

    def __init__(self, x=None, y=None, z=None):
        if x is not None:
            self.x = x
        elif x is not None:
            self.y = y
        elif z is not None:
            self.z = z
        else:
            raise ValueError('Provide an x, y, or z value.')

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

    @x.setter
    def x(self, value):
        self._x = x

    @property
    def y(self):
        return self._x / 2.0

    @y.setter
    def y(self, value):
        self._x = 2 * value

    @property
    def z(self):
        return self._x / 4.0

    @z.setter
    def z(self, value):
        self._x = 4 * value

因此,我们在类上只存储了一个_x 属性,而所有其余的getter 和setter 都使用_x 属性(我们当然可以使用_y_z 来代替)。

此外,不是很优雅的事情是程序员可以实例化Foo(x=1, y=425)。如您所见,这意味着它包含不一致。在这种情况下,也许值得提出一个错误。

您可以通过在 init 模块中添加以下检查来确保您只提供一个参数:

class Foo(object):

    def __init__(self, x=None, y=None, z=None):
        data = [i for i in [x, y, z] if i is not None]
        if len(data) > 1:
            raise ValueError('Multiple parameters provided.')
        if x is not None:
            self.x = x
        elif x is not None:
            self.y = y
        elif z is not None:
            self.z = z
        else:
            raise ValueError('Provide an x, y, or z value.')

    # ...

这里我们因此构造了一个所有非None值的列表,如果有多个值,程序员提供了两个或多个值,那么最好引发异常。

【讨论】:

  • 为了避免“不一致”,在if 子句上添加更多条件是一件简单的事情:if x is not None and y is None and z is None: 。并对所有其他 2 种情况执行相同操作,但这会疯狂增长(如果有更多参数)。还有其他优雅的方法吗?
  • 好主意,这样做了:if sum(i is not None for i in locals().values()) > 2: raise ValueError("...")。谢谢。
猜你喜欢
  • 2015-06-29
  • 2011-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多