Python 如何实现@property
我比较了python中Python 如何实现@property,python,decorator,Python,Decorator,我比较了python中@property的三种稍微不同的实现。Python文档和“源代码1”初始化私有变量\u var\u name。此外,源代码1中的代码有一个bug;初始化时,它不访问.setter。相比之下,第三个示例正确地初始化了公共变量x 是否有充分的理由初始化\ux以代替\uuu init\uu中的x?这两者之间还有什么我没有描述的区别吗 从: : class摄氏度: def _初始(自身,温度=0): 自身温度=温度 def至华氏温度(自身): 返回(自身温度*1.8)+32 @财
@property
的三种稍微不同的实现。Python文档和“源代码1”初始化私有变量\u var\u name
。此外,源代码1中的代码有一个bug;初始化时,它不访问.setter
。相比之下,第三个示例正确地初始化了公共变量x
是否有充分的理由初始化\ux
以代替\uuu init\uu
中的x
?这两者之间还有什么我没有描述的区别吗
从:
:
class摄氏度:
def _初始(自身,温度=0):
自身温度=温度
def至华氏温度(自身):
返回(自身温度*1.8)+32
@财产
def温度(自身):
打印(“获取价值”)
返回自身温度
@温度调节器
def温度(自身、数值):
如果值<-273:
提升值错误(“温度不可能低于-273”)
打印(“设置值”)
自身温度=数值
:
P类:
定义初始化(self,x):
self.x=x
@财产
def x(自我):
返回自我
@x、 塞特
def x(self,x):
如果x<0:
自。uux=0
elif x>1000:
自整角x=1000
其他:
自
是否有充分的理由初始化\uuux
或\ux
以代替\uuuu init\uux
中的x
属性通常用于以某种方式转换输入。内部方法(包括\uuuu init\uuuu
)通常已经具有转换后的数据,并且不希望再次对其进行转换。例如,考虑这个有点傻但很明显的例子:
class C:
# ...
def __init__(self):
f = open(C.default_filename, 'rb')
# ...
self._file = f
@property
def file(self):
return self._file.__name__
@file.setter
def file(self, filename):
self._file = open(f, 'rb')
即使您没有做任何错误的事情来通过setter,内部代码通常也知道类不变量,因此setter所做的检查可能是额外的开销,没有任何好处。例如,如果您想要一种将温度设置为0°C的方法,它可以只设置self.\u x=0
而不是self.x=0
,因为您知道0
不需要检查
另一方面,一些内部方法可能希望以与公共方法相同的方式查看x
。在这种情况下,它应该使用属性而不是基础属性。事实上,您的源代码1是一个完美的例子-\uuuu init\uuuuu
只是将其参数直接保存到\u temperature
,允许您构造绝对0以下的温度(这是不好的,因为它实际上比无穷大更热,而且CPU喜欢冷)。在\uuuu init\uuuuu
中重复您在temperature.setter
中编写的相同前提条件测试是愚蠢的;在这种情况下,只需设置self.temperature
使用单下划线还是双下划线还有其他区别 单个下划线使属性“按约定为私有”;双下划线更进一步,这意味着不能从类代码外部意外访问它
使用
obj.\u x
可以在您的实例上工作<代码>对象.\uuux引发属性错误
。但这只能防止意外访问,如果他们真的想访问,他们仍然可以使用obj.\u C\u x。这样做的主要原因是为了防止子类或超类意外使用相同的名称。另一个区别是摄氏度。温度是一个非常有意义的名称,而p.x
,谁知道它是什么意思,或者为什么它被限制为0-1000。但我相信你已经知道了。那么,您建议如何解决示例“Source 1”中的问题,其中c=Celsius(-100)
不调用setter
?@anon01正如我在回答中所说的,这是一个很好的情况,您可能希望调用setter只需执行self.temperature=temperature
。(虽然在回答中,我把它弄混了,称它为x
vs.\ux
而不是温度vs.\uTemperature
;我会解决这个问题……)
class Celsius:
def __init__(self, temperature = 0):
self._temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self._temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self._temperature = value
class P:
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 > 1000:
self.__x = 1000
else:
self.__x = x
class C:
# ...
def __init__(self):
f = open(C.default_filename, 'rb')
# ...
self._file = f
@property
def file(self):
return self._file.__name__
@file.setter
def file(self, filename):
self._file = open(f, 'rb')