关于python 3中@property的一些疑问

时间:2019-03-20 15:02:15

标签: python

为了不让自己过度张扬,我将举一个我想做的基本假设假设。 假设以下类别:

class foo():
   def __init__(self):
      self.keywords = []

   ## this method returns the entire list
   def get_keywords(self):
      return self.keywords

   def set_keywords(self, value):
      self.keywords.append(value)

但是我想使用@property装饰器以pythonic方式编写代码。 我(错误的)尝试这样做:

class foo:
    def __init__(self):
        self.key = []

    @property
    def key(self):
        return self.__key

    @key.setter
    def key(self, value):
        self.__key.append(value) 

那么,我的尝试出了什么问题? ps:英语不是我的母语,我希望我的疑问可以理解。

2 个答案:

答案 0 :(得分:1)

在您的原始代码中,self.set_keywords 附加到现有列表中;它不允许您将keywords的值初始化为任意列表。此限制保留在基于property的代码中,这意味着您无法直接分配给self.key;您必须直接在__init__中初始化基础列表。

class foo:
    def __init__(self):
        # self.key = [] is equivalent to `self.__key.append([])`, but
        # self.__key doesn't exist yet. (And would be wrong even if it did.)
        self.__key = []

    @property
    def key(self):
        return self.__key

    @key.setter
    def key(self, value):
        self.__key.append(value) 

但是,这意味着像self.key = 3这样的作业实际上并没有执行大多数人期望的作业。它不会覆盖旧值,而是添加到旧值中。使用设置器提供一个固定列表,但使用另一种方法将其添加到现有列表中。

class foo:
    def __init__(self):
        self.__keys = []

    @property
    def keys(self):
        return self.__keys

    @keys.setter
    def keys(self, values):
        self.__keys = values

    def add_key(self, value):
        self.__key.append(value) 

最后,如果您实际上没有在getter或setter中做任何额外的工作或验证,则使用属性不一定是Pythonic。如果您要做的只是包装对基础值的访问,只需直接使用该值即可。

class foo:
    def __init__(self):
        self.keys = []

self.keys = [1,2,3]
print(self.keys)
self.keys.append(4)
# etc

关于属性的好处是,如果您通过允许直接访问keys开始,那么关于keys的使用方式没有任何变化如果您以后决定将其替换为属性。

答案 1 :(得分:0)

您可以尝试一下:

class Foo:
    def __init__(self):
        self._key = []

    @property
    def key(self):
        return self._key

    @key.setter
    def key(self, value):
        self._key = value

这是我的两分钱

  • 将类foo重命名为Foo
  • 您无法初始化self.key,因为这是属性,因此请在构造函数中初始化正确的变量(即__init__
  • 私有变量以一个_范围为前缀,而不是两个(两个__是Python内部函数)
  • 我想您宁愿希望my_instance.key = ['spam', 'eggs']替换foo._key值而不是扩展它。因为这是一个“设定者”,并且会导致怪异的行为,或者至少另一个开发人员不会期望该设定者/函数的这种行为

但是,这很重要:只要您仅这样做,就不需要属性。您只需在构造函数和froget中初始化有关属性和setter函数的self.keys即可。稍后,当您想要更改行为时,仍然可以添加属性和设置器。这就是我们在Python中拥有属性的原因之一,这样您就不必重构整个代码,以防出现“更多逻辑”。

顺便说一句。如果您真的要依赖于所有dict函数,那么您可能还想从dict类继承您的类。取决于您的工作。