Python:多个属性,一个设置器/获取器

17 投票
4 回答
14665 浏览
提问于 2025-04-15 18:22

考虑以下的类定义

class of2010(object):
    def __init__(self):
        self._a = 1
        self._b = 2
        self._c = 3

    def set_a(self,value):
        print('setting a...')
        self._a = value
    def set_b(self,value):
        print('setting b...')
        self._b = value
    def set_c(self,value):
        print('setting c...')
        self._c = value
    a = property(fset=self.set_a)
    b = property(fset=self.set_b)
    c = property(fset=self.set_c)

注意到 set_[a|b|c]() 这几个方法做的事情是一样的。有没有办法定义一个:

def set_magic(self,value):
    print('setting <???>...')
    self._??? = value

只定义一次,然后可以用在a、b、c上,像这样

a = property(fset=self.set_magic)
b = property(fset=self.set_magic)
c = property(fset=self.set_magic)

4 个回答

3

也许你在找的是 __setattr__(self, name, value)

你可以在 这里 看看

7

我注意到你的设置方法只是记录一条消息,然后简单地赋值——实际上,你接受的答案只是赋值。你这样做是因为这是某种语言中被广泛接受的做法吗?也许那种语言的名字是以“J”开头的?如果是这样的话,请了解在Python中,这种设计的更简单的做法是:

class Of2010(object):
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

没有无所作为的设置方法,也没有为了赋值而进行的中间函数调用。“什么?!”你会说。“公开暴露成员变量?!!”其实,是的

从客户端代码的角度来看这些类。要使用你的类,客户端需要创建一个对象,然后用以下方式赋值属性“a”:

obj = Of2010()
obj.a = 42

令人惊讶的是,这和我上面发布的五行代码是完全一样的。

为什么J语言鼓励使用更冗长的属性风格呢?是为了在未来需求变化时保持类的接口。如果在某个时刻,对象的其他值必须与“a”的变化一起改变,那么你就必须实现属性机制。可悲的是,J语言将属性访问机制的本质暴露给客户端代码,因此在未来引入一个属性将变成一个侵入性的重构任务,这需要重建所有使用该类及其“a”属性的客户端。

而在Python中,情况并非如此。对对象“a”属性的访问是在调用时决定的。由于直接访问和属性访问看起来是一样的,你的Python类在接口上保持一致,尽管实际机制不同。重要的是,从客户端代码的角度来看,它们是相同的。

所以在Java中,从这个类一开始就引入了这种属性复杂性(实际上,根据被接受的做法,所有类都是如此),以防将来某一天可能需要。而在Python中,可以先实现最简单的可行方案,也就是直接访问简单的成员变量,复杂的做法可以留到未来真正需要的时候再去实现。因为那一天可能永远不会到来,这在让你的代码尽快发布第一个可用版本上是一个巨大的进步。

21

这个代码块是用来展示一些编程内容的,具体的内容在这里没有给出。通常情况下,代码块会包含一些示例代码或者特定的编程指令,帮助人们理解如何实现某个功能。

如果你看到这样的代码块,通常意味着这里有一些重要的代码需要你去学习或者参考。记得仔细查看这些代码,它们可能会对你理解整个问题有很大帮助。

def attrsetter(attr):
  def set_any(self, value):
    setattr(self, attr, value)
  return set_any

a = property(fset=attrsetter('_a'))
b = property(fset=attrsetter('_b'))
c = property(fset=attrsetter('_c'))

撰写回答