鉴于以下课程:
class BasicRNNCell(RNNCell):
"""The most basic RNN cell."""
def __init__(self, num_units, input_size=None):
self._num_units = num_units
self._input_size = num_units if input_size is None else input_size
@property
def input_size(self):
return self._input_size
@property
def output_size(self):
return self._num_units
@property
def state_size(self):
return self._num_units
def __call__(self, inputs, state, scope=None):
"""Most basic RNN: output = new_state = tanh(W * input + U * state + B)."""
with vs.variable_scope(scope or type(self).__name__): # "BasicRNNCell"
output = tanh(linear([inputs, state], self._num_units, True))
return output, output
我不明白为什么他们在这种情况下使用属性函数。使用input_size函数的属性装饰器允许一个人调用一个对象上的input_size,让我们称之为该类的单元格,但为什么不调用cell._input_size呢?谁能告诉我为什么这有用呢?
答案 0 :(得分:7)
与您建议的直接成员访问相比,使用Python属性具有优势。
考虑实施
class Foo(object):
def __init__(self):
self.bar = ...
VS
class Foo(object):
def __init__(self):
self._bar = ...
...
@property
def bar(self):
return self._bar
假设您有foo = Foo()
。在前一种情况下,您以foo.bar
的身份访问该成员。这意味着你可以做到
print foo.bar
foo.bar = 3
即,您无法控制对bar
的修改。在后一种情况下,尽管如此 - 无可否认地依赖于convention not to access things prefixed with _
- 你可以做到
print foo.bar
但
foo.bar = 3
会引发异常。
此外,使用property setters,您可以控制bar
的修改方式,并进行验证和其他很酷的内容:
class Foo(object):
def __init__(self):
self._bar = ...
...
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, value):
if something_of_value(value):
raise Whatever
self._bar = value
答案 1 :(得分:4)
(拙见意见模式:ON)
我认为这是滥用财产。在当天,C ++和Java程序员意识到暴露公共类成员会使他们的代码变得脆弱。在不改变类接口和破坏向后兼容性的情况下,您无法改变关于如何生成该变量的数据的想法。因此,人们开始使用getter和setter(访问私有成员的函数)以增加灵活性,并且有一种隐藏所有成员的推动......以防万一。
当其他语言形式化属性时,它们有时会遇到类接口的相同问题。如果不更改接口并再次破坏向后兼容性,则无法从变量更改为属性。因此,推动所有变量属性......以防万一。
Python不是这样的。您今天可以拥有成员foo
,明天将其更改为属性,类界面不会更改。在我看来,这只是一种来自另一种语言的防御性编码实践,在这里不需要。
(拙见意见模式:OFF)