【问题标题】:Dynamic python properties动态 python 属性
【发布时间】:2014-12-30 22:06:38
【问题描述】:

好的,我重新表述我的问题,因为我的动机不够明确。

我们有一个类,用户将使用更复杂的存储/检索机制实际实现的属性填充该类。 我在下面简化了它。 假设存储机制现在只是一个简单的字典:

class MyClass:
    def __init__(self, d):
        self.mydict = d

    def getterX(self):
        return self.mydict['X']
    def setterX(self, val):
        self.mydict['X'] = val
    X = property(getterX, setterX)

    def getterY(self):
        return self.mydict['Y']
    def setterY(self, val):
        self.mydict['Y'] = val
    Y = property(getterY, setterY)

da = {}
Ma = MyClass(da)

Ma.X = 5
Ma.Y = 6
print(Ma.X, Ma.Y)   #outputs 5 6
print(da)           #outputs {'Y': 6, 'X': 5}

这很好用,除了它很容易出错和冗长。 它需要五行,其中不少于 7X 实例,需要为每个新属性剪切+粘贴。 其中一些类可能有几十个属性。

代替使用宏(我认为 Python 不支持,而且效率低下),我试图通过一些辅助函数来简化它:

da = {}

class MyHelper:
    def __init__(self, dict, label):
        self.mydict = dict
        self.mylabel = label

    def getter2(self, other):
         return self.mydict[self.mylabel]

    def setter2(self, other, value):
        self.mydict[self.mylabel] = value

def makeProperty(d, label):
    H = MyHelper(d, label)
    return property(H.getter2, H.setter2)

class MyClass:
    def __init__(self, d):
        self.mydict = d

    X = makeProperty(da, 'X')  #da is global, but should be self.mydict
    Y = makeProperty(da, 'Y')  #  " " "

Ma = MyClass(da)

Ma.X = 5
Ma.Y = 6
print(Ma.X, Ma.Y)   #outputs 5 6
print(da)           #outputs {'Y': 6, 'X': 5}

现在这个几乎可以工作了,除了调用 ma​​keProperty() 需要访问全局变量 da,而不是使用 self 成员数据。

这是我遇到的难题,但我倾向于相信这是可能的,因为第一个代码示例在其 getter/setter 中访问 self 成员数据。

希望这能让事情变得更清楚。 谢谢, 抢。

更多信息:

我认为这个解决方案行不通,因为 makeProperty 调用似乎只被调用一次,而不是我假设的每个类实例化一次。

那么有什么办法可以让这个工作,或者用户被降级为大量的剪切+粘贴?

【问题讨论】:

  • 你到底应该是什么?
  • 我不明白你想在这里做什么。您可以拥有类本身并将其分配变量或将变量分配给类实例。我无法想到会实现这一点(因为它对我来说没有意义)。也许如果你更详细地解释你到底想要实现什么,我可以提供更多帮助
  • 例如在公共存储库中镜像的属性。
  • addCustomProperty 是未定义的,我也确定......因为我在任何地方都没有看到......
  • 您可能想解释一下为什么首先需要生成属性

标签: python properties


【解决方案1】:

考虑到问题“MyClass 的每个实例都可以为属性 y 提供唯一的 getter/setter 函数吗?”,字面上的答案是“否”——描述符(包括 property)在类上查找,而不是在实例。

但是,类级描述符可以委托给实例持有的可调用对象,从而产生类似的效果。您的示例对我来说并不完全清楚,但是,例如:

class Whatever(object):

    def __init__(self, scale, getter=lambda x: 42):
        self.scale = scale
        self.getter = getter

    @property
    def y(self):
        return self.getter(self.scale)

plain = Whatever(33)
fancy = Whatever(47, lambda x: x*2)

现在plain.y 将变为42,忽略plain.scale,即使它已更改;而fancy.y 最初将是94,但如果fancy.scale 发生更改,则更改。那是你想做的事情吗?看到所需的用例肯定会有所帮助...

补充:鉴于我们在 Q 的大型编辑中看到了一个简化的用例,以下是我将如何解决它:

class MyHelper:
    def __init__(self, label):
        self.mylabel = label

    def getter2(self, other):
        return other.mydict[self.mylabel]

    def setter2(self, other, value):
        other.mydict[self.mylabel] = value

def makeProperty(label):
    H = MyHelper(label)
    return property(H.getter2, H.setter2)

class MyClass:
    def __init__(self, d):
        self.mydict = d

    X = makeProperty('X')
    Y = makeProperty('Y')

可以通过将MyHelper 的方法名称更改为__get____set__ 来省略工厂函数makeProperty(即,将MyHelper 本身变成一个描述符类型)并调用MyHelper直接构建要分配的实例,但这种稍微不那么直接的方法可能更容易理解,因为它依赖于众所周知的内置类型property

【讨论】:

  • 您好,为了清楚起见,我在上面完全改写了我的问题。我不确定您的信息是否仍然适用。感谢您的意见。
  • 是的,谢谢,今天早上我想到了,我不需要将 self 传递给 makeProperty,因为它可以作为 getter/setter 调用中的“其他”参数使用。感谢您确认并提供额外的解释。
猜你喜欢
  • 2015-08-15
  • 2018-04-16
  • 2015-08-24
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-26
相关资源
最近更新 更多