【问题标题】:The pythonic way to construct a multimethod setter构造多方法设置器的pythonic方法
【发布时间】:2025-12-18 06:30:01
【问题描述】:

我们可以使用@property 来构造getter 和setter。这是我们如何做到这一点的一个简短示例:

class A:

    def __init__(self,x):
        self.x = x

    @property
    def x(self):
        return self.__x

    @x.setter
    def x(self, x):
        if x < 0:
            self.__x = 0
        elif x > 100:
            self.__x = 100
        else:
            self.__x = x

我的情况似乎更复杂。

class A:

    def __init__(self, x):
        self.__x = x
        self.x1()
        self.x2()
        self.x3()

    def x1(self):
        self.__x1 = self.__x + 1
        return self.__x1

    def x2(self):
        self.__x2 = self.__x1 + 2
        return self.__x2

    def x3(self):
        self.__x3 = self.__x2 + 3
        return self.__x3


if __name__ == "__main__":
    a = A(3)
    print(a.x3)

方法x1x2x3 过于简单。当调用__init__ 方法时,self.__x3 变量只设置一次。现在,我需要一个getter 方法来通过调用a.x3 来获取self.__x3。如何以 Python 的方式实现?

【问题讨论】:

  • 我建议将您的问题分解为一个通用问题,因为有很多与它无关的信息,我个人并不能真正理解您要做什么。
  • 请提供您的整个班级 - 很难理解您的问题是什么。
  • 我已经简化了描述并添加了考虑的类。
  • 这里没有动机,我不知道你为什么还要写 x1/x2/x3 作为变异方法,而只有 __init__ 使用它们,而你可以编写内部辅助函数(例如 _x1/_x2/_x3__init__ 使用)并为 x1/x2/x3 使用常规非变异属性(供公众使用)。这很臭an XY problem。即使这样有效,外部用户对x3的使用应该修改__x3,还是直接返回?
  • @ShadowRanger 你是对的。我在方法名称之前考虑了_。我在编辑我的帖子之前询问了它以便更容易理解。不,__x3 不能修改。现在我看到您的解决方案(xN 的非变异属性)是我所需要的。

标签: python python-3.x class getter-setter


【解决方案1】:

尝试基于您希望仅在 __init__ 期间修改 __x# 变量且不再修改的假设的答案,但还希望访问器遵循相同的代码路径(可能是因为读取在编程上也很复杂) :

在这种情况下,您可以让实现函数采用额外的默认参数。当以属性形式访问时,它将接收默认参数,但如果显式访问属性的fget 成员,则可以使用非默认参数调用它。仅针对 x1 的简单示例:

class A:

    def __init__(self, x):
        self.__x = x
        # Access the property itself off the class, bypassing execution,
        # then call it directly with the non-default argument
        type(self).x1.fget(self, True)

    @property
    def x1(self, doset=False):
        if doset:
            self.__x1 = self.__x + 1
        return self.__x1

或者,为了简化__init__ 中的用法,您可以为底层函数使用单独的名称而不是property 以达到相同的效果:

class A:

    def __init__(self, x):
        self.__x = x
        # Call the implementing function directly with the non-default argument
        self._x1(True)

    # Implementing function named with single underscore prefix to indicate it's
    # for internal/protected use only
    def _x1(self, doset=False):
        if doset:
            self.__x1 = self.__x + 1
        return self.__x1
    # Define property x1 based on x1 for outside use
    x1 = property(_x1)

当然,如果你没有复杂的getter路径,那么真正的解决方案是将_x1x1完全分开,其中_x1__init__的纯setter辅助函数,@987654333 @ 是纯吸气剂:

class A:

    def __init__(self, x):
        self.__x = x
        # Call the init helper
        self._init_x1()

    # Implementing function named with single underscore prefix to indicate it's
    # for internal/protected use only
    def _init_x1(self):
        self.__x1 = self.__x + 1

    @property:
    def x1(self):
        return self.__x1

明确地说,只有最后一个是“Pythonic” 在任何有意义的意义上。第二个选项有一些有限的用例(你有一个需要存在的函数,并且是高度可配置的,但有一组合理的默认值,property 可以使用),但在这种情况下,它通常是一个函数公共实用程序就像property。选项 #1 是最不符合 Pythonic 的,因为它使用起来不方便(需要提升到类类型,提取 fget 成员,并显式传递 self),并且非常清楚地表明没有预期的外部用例的__init__(因为使用起来很痛苦,没人会打扰)。

【讨论】:

    最近更新 更多