构建多方法的 pythonic 方式 setter
The pythonic way to construct a multimethod setter
我们可以用一个@property
构造一个getter和setter。这是我们如何做到这一点的简短示例:
class A:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 100:
self.__x = 100
else:
self.__x = x
我的情况好像比较复杂
class A:
def __init__(self, x):
self.__x = x
self.x1()
self.x2()
self.x3()
def x1(self):
self.__x1 = self.__x + 1
return self.__x1
def x2(self):
self.__x2 = self.__x1 + 2
return self.__x2
def x3(self):
self.__x3 = self.__x2 + 3
return self.__x3
if __name__ == "__main__":
a = A(3)
print(a.x3)
方法 x1
、x2
和 x3
过于简单化。 self.__x3
变量仅在调用 __init__
方法时设置一次。现在,我需要一个 getter 方法来通过调用 a.x3
来获取 self.__x3
。如何以 pythonic 方式实现?
基于您希望仅在 __init__
期间修改 __x#
变量并且永远不会再次修改的假设来尝试回答,而且还希望访问器遵循相同的代码路径(可能是因为read 在编程上也很复杂):
在这种情况下,您可以让实现函数采用额外的默认参数。当以属性形式访问时,它将接收默认参数,但如果显式访问 属性 的 fget
成员,则可以使用 non-default 参数调用它。一个仅针对 x1
的简单示例:
class A:
def __init__(self, x):
self.__x = x
# Access the property itself off the class, bypassing execution,
# then call it directly with the non-default argument
type(self).x1.fget(self, True)
@property
def x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
或者,为了简化 __init__
中的用法,您可以为底层函数使用单独的名称,而不是 property
以达到相同的效果:
class A:
def __init__(self, x):
self.__x = x
# Call the implementing function directly with the non-default argument
self._x1(True)
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
# Define property x1 based on x1 for outside use
x1 = property(_x1)
当然,如果你没有复杂的getter路径,那么真正的解决办法是将_x1
和x1
完全分开,其中_x1
是__init__
的纯 setter 辅助函数,x1
是纯 getter:
class A:
def __init__(self, x):
self.__x = x
# Call the init helper
self._init_x1()
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _init_x1(self):
self.__x1 = self.__x + 1
@property:
def x1(self):
return self.__x1
明确地说,只有最后一个在任何意义上都是 "Pythonic"。第二个选项有一些有限的用例(你有一个需要存在的函数,并且是高度可配置的,但有一组合理的默认值 property
可以使用),但在那种情况下,它通常是一个函数与 property
一样具有 public 实用性。选项 #1 是最少的 Pythonic,因为它使用起来不方便(需要提升到 class 类型,提取 fget
成员,并显式传递 self
),并且非常清楚__init__
之外没有预期的用例(因为使用起来很痛苦,没有人会打扰)。
我们可以用一个@property
构造一个getter和setter。这是我们如何做到这一点的简短示例:
class A:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 100:
self.__x = 100
else:
self.__x = x
我的情况好像比较复杂
class A:
def __init__(self, x):
self.__x = x
self.x1()
self.x2()
self.x3()
def x1(self):
self.__x1 = self.__x + 1
return self.__x1
def x2(self):
self.__x2 = self.__x1 + 2
return self.__x2
def x3(self):
self.__x3 = self.__x2 + 3
return self.__x3
if __name__ == "__main__":
a = A(3)
print(a.x3)
方法 x1
、x2
和 x3
过于简单化。 self.__x3
变量仅在调用 __init__
方法时设置一次。现在,我需要一个 getter 方法来通过调用 a.x3
来获取 self.__x3
。如何以 pythonic 方式实现?
基于您希望仅在 __init__
期间修改 __x#
变量并且永远不会再次修改的假设来尝试回答,而且还希望访问器遵循相同的代码路径(可能是因为read 在编程上也很复杂):
在这种情况下,您可以让实现函数采用额外的默认参数。当以属性形式访问时,它将接收默认参数,但如果显式访问 属性 的 fget
成员,则可以使用 non-default 参数调用它。一个仅针对 x1
的简单示例:
class A:
def __init__(self, x):
self.__x = x
# Access the property itself off the class, bypassing execution,
# then call it directly with the non-default argument
type(self).x1.fget(self, True)
@property
def x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
或者,为了简化 __init__
中的用法,您可以为底层函数使用单独的名称,而不是 property
以达到相同的效果:
class A:
def __init__(self, x):
self.__x = x
# Call the implementing function directly with the non-default argument
self._x1(True)
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
# Define property x1 based on x1 for outside use
x1 = property(_x1)
当然,如果你没有复杂的getter路径,那么真正的解决办法是将_x1
和x1
完全分开,其中_x1
是__init__
的纯 setter 辅助函数,x1
是纯 getter:
class A:
def __init__(self, x):
self.__x = x
# Call the init helper
self._init_x1()
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _init_x1(self):
self.__x1 = self.__x + 1
@property:
def x1(self):
return self.__x1
明确地说,只有最后一个在任何意义上都是 "Pythonic"。第二个选项有一些有限的用例(你有一个需要存在的函数,并且是高度可配置的,但有一组合理的默认值 property
可以使用),但在那种情况下,它通常是一个函数与 property
一样具有 public 实用性。选项 #1 是最少的 Pythonic,因为它使用起来不方便(需要提升到 class 类型,提取 fget
成员,并显式传递 self
),并且非常清楚__init__
之外没有预期的用例(因为使用起来很痛苦,没有人会打扰)。