【问题标题】:When using property decorator, should the variable be declared as public or private in __init__?使用属性装饰器时,变量应该在__init__中声明为public还是private?
【发布时间】:2021-06-11 04:17:27
【问题描述】:

让我们考虑两个实现:

class A:
    def __init__(self, myvar):
        self._myvar = myvar # 

    @property
    def myvar(self):
        print("GET")
        return self._myvar

    @myvar.setter
    def myvar(self, newvar):
        print("SET")
        self._myvar = newvar

class B:
    def __init__(self, myvar):
        self.myvar = myvar

    @property
    def myvar(self):
        print("GET")
        return self._myvar

    @myvar.setter
    def myvar(self, newvar):
        print("SET")
        self._myvar = newvar

唯一的区别在于__init__,我们在 A 类中初始化了 _myvar,在 B 类中初始化了 myvar

a = A(myvar=5)
print(a.myvar)

会输出

GET
5

b = B(myvar=5)
print(b.myvar)

会输出

SET
GET
5

总而言之,据我了解,这两种实现方式的唯一区别在于 init. A 类的实例将直接设置 _myvar,而 B 类的实例将通过 myvar.setter 设置 _myvar。 所以我的问题如下: 哪个实现被认为更 Pythonic?有理由使用其中一个吗?

【问题讨论】:

    标签: python properties decorator python-internals


    【解决方案1】:

    class B 是更好的做法。

    假设您在setter 中有一些验证步骤,例如您想确保仅将特定范围内的值设置为myvarclass B 将确保验证步骤甚至通过构造函数运行。但是对于class A,您将直接更新变量,在这种情况下,setter 方法中的验证步骤将被跳过。

    class EvenOnly_A:
      def __init__(self, myvar):
          self._myvar = myvar # 
    
      @property
      def myvar(self):
          return self._myvar
    
      @myvar.setter
      def myvar(self, newvar):
          assert newvar%2 == 0
          self._myvar = newvar
    
    
    class EvenOnly_B:
      def __init__(self, myvar):
          self.myvar = myvar
    
      @property
      def myvar(self):
          return self._myvar
    
      @myvar.setter
      def myvar(self, newvar):
          assert newvar%2 == 0
          self._myvar = newvar 
    
    a = EvenOnly_A(3)
    b = EvenOnly_B(3)
    

    【讨论】:

      【解决方案2】:
      1. python 中没有真正的私有属性。人们总是可以访问它,例如a._myvar = 2。这只是一个约定——“我们都是成年人,你不应该搞砸这个”(更多详情请参阅here
      2. 在python 中有getter 和setter 的原因是你想执行一些额外的代码。否则就不需要使用 getter 和 setter。

      假设你确实想在你设置属性值的时候执行额外的代码,B类是正确的实现,因为A类不会执行额外的代码。

      【讨论】:

        【解决方案3】:

        我想提请注意,您的代码有一些问题。比如——

        在您的 B 类中,您在 init 方法中将变量定义为本地变量,但在您的 setter 方法中,您使用的是私有方法。

        class B:
            def __init__(self, myvar):
                self.myvar = myvar
        
            @property
            def myvar(self):
                print("GET")
                return self._myvar
        
            @myvar.setter
            def myvar(self, newvar):
                print("SET")
                self._myvar = newvar
        

        self.__myvarself.var 是两个不同的东西。

        所以下面这段代码会导致无限循环

        
        class B:
            def __init__(self, myvar):
                self.myvar = myvar
        
            @property
            def myvar(self):
                print("GET")
                return self.myvar
        
            @myvar.setter
            def myvar(self, newvar):
                print("SET")
                self.myvar = newvar
        b = B(myvar=5)
        print(b.myvar)
        
        
        

        现在,我想强调一下,在 Python 中,您需要小心处理私有变量。

        【讨论】:

          猜你喜欢
          • 2010-10-17
          • 1970-01-01
          • 2012-12-23
          • 1970-01-01
          • 1970-01-01
          • 2012-12-08
          • 2010-11-27
          • 2011-02-13
          • 1970-01-01
          相关资源
          最近更新 更多