Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data-Binding in Python?

I readily admit that I might be referring to this by the wrong name or wanting something that I shouldn't need. I'm just hung up on wanting this to be a thing: linking together object attributes so that if I change one, that I'll change the other. Always. Until I do something to disconnect them on purpose.

So let's go straight into an example:

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")

So now a.name and b.name are connected so that they both are names for the same mutable, which now reads ["Thing2"]. And further, c.name is a name of a different value ["Thing1"].

I've now accomplished what I want to do: a.name and b.name are linked. But this is tremendously kludgy.

I could make a custom list Class and create some methods to switch out the thing in the list and return an immutable when called, so that it looks more like a normal immutable. But all that seems like a hack.

Any thoughts on making this cleaner? Or am I simply wanting a bad thing?

like image 921
raiderrobert Avatar asked Mar 12 '15 20:03

raiderrobert


People also ask

What is meant by data binding?

What is data binding? Data binding is the process that establishes a connection between the app UI and the data it displays. If the binding has the correct settings and the data provides the proper notifications, when the data changes its value, the elements that are bound to the data reflect changes automatically.

What is data binding and its types?

In simple words, you can say that data binding is a communication between your typescript code of your component and your template which user sees. It makes easy to define interactive applications without worrying about pushing and pulling data. Data binding can be either one-way data binding or two-way data binding.

What is the syntax of data binding?

Two-way data binding will perform two things i.e. setting of the element property and listening to the element change events. The syntax of two way binding is – [( )}. As you can see, it is a combination of the property binding syntax i.e. [ ] and the event binding syntax ( ).


1 Answers

In general, when you do re-definition

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

x and y will no longer reference the same thing (try print id(x) == id(y)).

Consider how re-definition works:

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]

What you can do, with mutable types is to change the object "in place".

For example,

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

Now, both x and y reference the same list (print id(x) == id(y)).

Now we can replace the elements, by using only x:

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

Here, we're not re-defining x, we're just modifying the values in the list.

In this case, the changes will be reflected in y:

print y     # Now [4,5,6]

Note:

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

If you want the ability to modify in-place an immutable type, you can "fake" it by wrapping it in a list:

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

There will be a million questions on here about mutable / immutable types -- you should review them.


Edit We could accomplish what you want with your bind line with a combination of mutable types and properties:

First, we create a "fake" mutable string 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

And to see how it works

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

Note that we don't re-assign to x -- instead we use the x.set() method. If we re-assigned to x, we'd ruin everything (as we talked about above).

Then, we can modify your Example class to the following:

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 instances have an attribute _name attribute that references a FakeMutableString object.

But with properties, we can pretend we're providing direct attribute access, while hiding the actual implementation.

So we can do something like:

# 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
like image 153
jedwards Avatar answered Sep 17 '22 04:09

jedwards