Python 中的数据绑定?

Data-Binding in Python?

我欣然承认我可能用错了名字来指代它,或者想要一些我不应该需要的东西。我只是挂断了希望这成为一件事:将对象属性链接在一起,这样如果我改变一个,我就会改变另一个。总是。直到我故意做点什么来断开它们。

那么让我们直接进入一个例子:

class Example:
    def __init__(self):
        self.name = ["Thing1"]

a = Example()
b = Example()
c = Example()

a.name = b.name

b.name.append("Thing2")
b.name.remove("Thing1")

现在 a.nameb.name 已连接,因此它们都是同一个可变变量的名称,现在显示为 ["Thing2"]。此外,c.name 是一个不同值的名称 ["Thing1"].

我现在已经完成了我想做的事情:a.nameb.name 已关联。但这是非常笨拙的。

我可以制作一个自定义列表 Class 并创建一些方法来切换列表中的内容,并且 return 在调用时成为不可变的,这样它看起来更像一个普通的不可变的。但这一切似乎都是黑客。

有没有让这个更干净的想法?还是我只是想要一件坏事?

一般情况下,当你重新定义时

x = 8
y = x
x = 4   # <-- Re-definition of x

xy 将不再引用相同的东西(尝试 print id(x) == id(y))。

考虑重新定义的工作原理:

x = 8
y = x
x = 4
print y     # Still 8

x = "foo"
y = x
x = "bar"
print y     # Still 'foo'

x = [1,2,3]
y = x
x = [4,5,6]
print y     # Still [1,2,3]

使用可变类型,您可以做的是更改对象"in place"。

例如,

x = [1,2,3]
y = x

现在,xy 引用同一个列表 (print id(x) == id(y))。

现在我们可以 替换 元素,只需使用 x:

x[:] = [4,5,6]

这里,我们不是重新定义x,我们只是修改列表中的值。

在这种情况下,更改 反映在 y:

print y     # Now [4,5,6]

注:

print id(x) == id(y)  # True

如果您希望能够就地修改不可变类型,您可以 "fake" 通过将其包装在列表中来实现:

x = ["Foo"]  # Strings are immutable
y = x
x[0] = "Bar"
print y               # ['Bar']
print id(x) == id(y)  # True

这里将有 100 万 个关于可变/不可变类型的问题——您应该查看它们。


Edit 我们 可以 通过 bind 行结合可变类型和 properties:

首先,我们创建一个 "fake" 可变字符串 class:

class FakeMutableString(object):
    def __init__(self, s=""):
        self.s = [s]

    def __str__(self):
        return self.s[0]

    def get(self):
        return self.s[0]

    def set(self, new):
        self.s[0] = new

看看它是如何工作的

x = FakeMutableString("Foo")
y = x
x.set("Bar")
print y             # Prints 'Bar' -- Change in x is reflected in y 

请注意,我们不会 重新分配给 x——而是使用 x.set() 方法。如果我们重新分配给 x,我们会毁了一切(正如我们上面所说的)。

那么,我们可以将你的Exampleclass修改为:

class Example(object):
    def __init__(self):
        self._name = FakeMutableString()

    @property
    def name(self):
        return self._name.get()

    @name.setter
    def name(self, new):
        self._name.set(new)

Example 实例具有引用 FakeMutableString 对象的 _name 属性。

但是对于属性,我们可以假装我们提供直接属性访问,同时隐藏实际实现。

所以我们可以这样做:

# Create Example instances
a = Example()
b = Example()
c = Example()

# Set their name attributes 
#   ( this actually calls <Example>._name.set() )
a.name = "ThingA"
b.name = "ThingB"
c.name = "ThingC"

# Access and print their name attributes
#   ( this actually calls <Example>._name.get() )
print a.name, b.name, c.name    # ThingA ThingB ThingC

# We can't bind like you suggested, but we can change what b._name points to
#   So here, we change b._name to point to the FakeMutableString a._name points to
b._name = a._name

# Now when we print the names, we see something different
print a.name, b.name, c.name    # ThingA ThingA ThingC

# And we can make a change in a, and have it reflected in b
a.name = "CommonName"
print a.name, b.name, c.name    # CommonName CommonName ThingC

# And vice-versa
b.name = "StillCommon"
print a.name, b.name, c.name    # StillCommon StillCommon ThingC