代码之家  ›  专栏  ›  技术社区  ›  anon01

如何实现@属性

  •  1
  • anon01  · 技术社区  · 6 年前

    我比较了 @property 在python中。Python文档和“Source 1”初始化私有变量, _var_name 。此外,源代码1中的代码有一个bug;它无法访问 .setter 初始化时。相比之下,第三个示例正确地初始化了公共变量 x

    是否有充分的理由初始化 _x 代替 x个 在里面 __init__ ?这两者之间有没有其他我没有描述的区别?

    docs :

    class C:
        def __init__(self):
            self._x = None
    
        @property
        def x(self):
            """I'm the 'x' property."""
            return self._x
    
        @x.setter
        def x(self, value):
            self._x = value
    
        @x.deleter
        def x(self):
            del self._x
    

    Source 1 :

    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
    

    Source 2 :

    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
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   abarnert    6 年前

    是否有充分的理由初始化 __x _x 代替 x 在里面 __init__ ?

    属性通常用于以某种方式转换输入。内部方法(包括 __初始化__ )通常已经 已转换的数据,并且不希望再次对其进行转换。例如,考虑一下这个有点愚蠢但显而易见的例子:

    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._x = 0 而不是 self.x = 0 因为你知道 0 不需要检查。

    另一方面,一些内部方法可能 希望 要查看 x个 公众也是这样做的。在这种情况下,它应该使用属性而不是基础属性。事实上,你的Source 1就是一个完美的例子 __初始化__ 只需将其参数直接保存到 _temperature ,允许您构造低于绝对0的温度(这很糟糕,因为它实际上比无穷大还要热,CPU喜欢冷)。在中重复相同的先决条件测试是愚蠢的 __初始化__ 你已经写进去了 temperature.setter ;在这种情况下,只需设置 self.temperature 相反


    使用单下划线还是双下划线还有其他区别。

    一个下划线使属性“按约定为私有”;双下划线更进一步 mangles the name ,这意味着不能从类代码之外意外访问它。

    使用 obj._x 处理您的实例; obj.__x 提高 AttributeError 。但它只能防止 意外的 他们仍然可以使用的访问 obj._C__x 如果他们真的想得到它。这样做的主要原因是为了防止子类或超类意外使用相同的名称。