使用Lambda创建getter和setter属性

14 投票
2 回答
17428 浏览
提问于 2025-04-15 13:21

我有这样的代码:

class X():
    def __init__(self):
        self.__name = None

    def _process_value(self, value):
        # do something
        pass

    def get_name(self):
        return self.__name

    def set_name(self, value):
        self.__name = self._process_value(value)

    name = property(get_name, set_name)

我可以用 lambda 函数来替代 get_nameset_name 吗?

我试过这样做:

name = property(lambda self: self.__name, lambda self, value: self.__name = self.process_value(value))

但是编译器不喜欢我的设置函数。

2 个回答

3

如果你想扩展一个 list(列表),你也可以使用 __setitem__,就像这样:

class Position(list):
    def __init__(self,x=0, y=0, z=0):
        super(Position, self).__init__((x,y,z))

    x = property(lambda self: self[0],
                 lambda self,value: self.__setitem__(0, value))
    y = property(lambda self: self[1],
                 lambda self,value: self.__setitem__(1, value))
    z = property(lambda self: self[2],
                 lambda self,value: self.__setitem__(2, value))
30

你的问题在于,lambda 的主体必须是一个表达式,而赋值是一个语句(在 Python 中这是一个很重要的区别)。如果你坚持使用 lambda,你会遇到很多类似的情况,并且会学到一些解决方法(通常会有解决办法,但并不总是),比如在这个例子中:

name = property(lambda self: self.__name, 
                lambda self, value: setattr(self, 
                                            '_X__name',
                                            self.process_value(value)))

也就是说,使用内置的 setattr(这是一个函数,因此可以在 lambda 的主体中使用)而不是赋值(赋值是一个语句,因此在 lambda 的主体中不可用)。

你还需要手动处理双下划线属性的名称混淆(将 __name 改为 _X__name,因为你在类 X 中),在这里属性名称以字符串的形式出现,因为在 setattr 中必须这样做,因为 Python 编译器只会对合适的标识符进行名称混淆,而不会对字符串字面量进行处理。

撰写回答