动态python属性

2024-04-27 04:25:42 发布

您现在位置:Python中文网/ 问答频道 /正文

好吧,我重新措辞我的问题,因为我的动机还不够清楚。你知道吗

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

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}

现在这个几乎正常工作,除了调用makeProperty()需要访问全局变量da,而不是使用自成员数据。你知道吗

这就是我所处的困境,但我倾向于相信这是可能的,因为第一个代码示例在getter/setter中访问自成员数据。你知道吗

希望这能让事情变得更清楚。 谢谢, 罗伯。你知道吗

更多信息:

我认为这个解决方案不起作用,因为makeProperty调用似乎只被调用一次,而不是像我假设的那样每个类实例化调用一次。你知道吗

那么,有没有办法让这项工作,或是用户降级到许多剪切+粘贴?你知道吗


Tags: selfreturn属性initdefmyclassvaloutputs
1条回答
网友
1楼 · 发布于 2024-04-27 04:25:42

给出这样一个问题:“MyClass的每个实例对于属性y是否都有唯一的getter/setter函数?”,字面上的答案是“no”,描述符(包括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')

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

相关问题 更多 >