使用属性装饰器时,变量在__init__中应该声明为public还是private?

When using property decorator, should the variable be declared as public or private in __init__?

让我们考虑两种实现方式:

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__ 我们在 class A 中初始化了 _myvar,在 class B

中初始化了 myvar
a = A(myvar=5)
print(a.myvar)

会输出

GET
5

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

会输出

SET
GET
5

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

  1. python 中没有真正的私有属性。人们总是可以访问它,例如a._myvar = 2。这只是一个惯例——“我们都是成年人,你不应该惹这个”(更多细节见here
  2. 在 python 中使用 getter 和 setter 的原因是您想执行一些额外的代码。否则就不需要使用 getters 和 setters.

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

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)

好吧,我想提请注意您的代码有一些问题。例如-

在您的 Class 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 中,您需要小心使用私有变量。