Python 中的数据绑定?

rai*_*ert 5 python data-binding

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

那么让我们直接来看一个例子:

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")
Run Code Online (Sandbox Code Playgroud)

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

我现在已经完成了我想要做的事情:a.name并且b.name是相互关联的。但这是非常笨拙的。

我可以创建一个自定义列表类并创建一些方法来切换列表中的事物并在调用时返回一个不可变的,这样它看起来更像一个普通的不可变的。但这一切似乎都是黑客攻击。

关于使这个更清洁的任何想法?还是我只是想要一件坏事?

jed*_*rds 5

一般来说,当你重新定义

x = 8
y = x
x = 4   # <-- Re-definition of x
Run Code Online (Sandbox Code Playgroud)

x并且y将不再引用相同的内容(尝试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]
Run Code Online (Sandbox Code Playgroud)

对于可变类型,您可以做的是“就地”更改对象。

例如,

x = [1,2,3]
y = x
Run Code Online (Sandbox Code Playgroud)

现在,无论是xy引用相同的列表(print id(x) == id(y))。

现在我们可以只使用以下元素来替换元素x

x[:] = [4,5,6]
Run Code Online (Sandbox Code Playgroud)

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

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

print y     # Now [4,5,6]
Run Code Online (Sandbox Code Playgroud)

笔记:

print id(x) == id(y)  # True
Run Code Online (Sandbox Code Playgroud)

如果您希望能够就地修改不可变类型,您可以通过将其包装在列表中来“伪造”它:

x = ["Foo"]  # Strings are immutable
y = x
x[0] = "Bar"
print y               # ['Bar']
print id(x) == id(y)  # True
Run Code Online (Sandbox Code Playgroud)

关于可变/不可变类型,这里有一百万个问题——你应该复习一下。


编辑我们可以bind使用可变类型和属性的组合完成您想要的行:

首先,我们创建一个“假”可变字符串类:

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
Run Code Online (Sandbox Code Playgroud)

看看它是如何工作的

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

请注意,我们不会重新分配给x-- 而是使用该x.set()方法。如果我们重新分配给x,我们会破坏一切(正如我们上面谈到的)。

然后,我们可以将您的Example类修改为以下内容:

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)
Run Code Online (Sandbox Code Playgroud)

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

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

所以我们可以这样做:

# 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
Run Code Online (Sandbox Code Playgroud)

  • @raiderrobert 我更新了我的答案,以说明您可以实现“绑定”目标的一种方式——它可能太多了,但总的来说,属性语言功能值得研究 (2认同)