-
-
Notifications
You must be signed in to change notification settings - Fork 721
bindableProperty of an object's copy is not bindable anymore #3995
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Thanks for reporting this problem, @balex89! And thanks for including a workaround. I've been thinking about it again and again over the past two months and I'm still undecided what to do about it. So far I see three options:
Option 1 is nice because it doesn't require any change to the existing binding implementation, but is hard to discover. Users will probably run into the problem first before noticing the need for this decorator. For simplicity's sake I tend towards option 2. What do you think? Would you like to create a pull request and see how it turns out? |
This PR follows #3995 issue discussion. I went with [Option 3](#3995 (comment)) for a list of reasons: 1. It uncompromisingly covers all aspects of the issue, including tracking of bindable attributes; 2. It doesn't really affect performance much, if done right (see below); 3. It isn't in fact as ridiculously complicated in terms of implementation as it might seem, once you see that it only adds a wrapper for function that reproduces an object instance. ## Impact on performance Since we modify `BindableProperty` setter method, i ran a simple test to measure impact on code performance when object is a) initialized and b) updated: ```py class TestClass: x = BindableProperty() def __init__(self): self.x = 1 def update(self): self.x = 2 init_time = timeit.timeit(lambda: TestClass(), number=1_000_000) a = TestClass() update_time = timeit.timeit(lambda: a.update(), number=1_000_000) print(f'creation: {init_time:.6f} s, update: {update_time:.6f} s') ```` I ran this test several times for the current and updated `BindableProperty` implementations and got following average figures: 1. For initialization it adds up to 5% performance time on average; 2. For update it adds ~1% (or less) time on average. Since a user, aiming to create millions of instances, each meant for binding, will probably face more sever issues for other reasons, the real-life overhead seems to be insignificant. --------- Co-authored-by: Falko Schindler <[email protected]>
Description
If we make a
copy.copy()
(or adeepcopy()
) of an object with abindableProperty
, the resulting copy's bindable attribute is not really bindable anymore (until its value is reassigned manually).Example
Why is that?
The
copy
module techniques do not invoke__setattr__()
at any point, so theBindableProperty.__set__()
method never gets to updatebinding.bindable_properties
with the new object'sid()
.And therefore, when binding, unexpectedly an active link will be created.
A workaround
A possible obvious approach might involve defining
__copy__
and__deepcopy__
methods for a target class and updatingbindable_properties
in the process.This works just fine for a trivial case. But I personally don't like it much, as it lacks universality and might get trickier if complicated by descriptors or unnecessary
__init__()
logic.What
copy
uses under the hood is thepickle
approach. From the docs:That leads us to the following solution:
This also is sufficient for the
__deepcopy__()
to work right.Possible solutions
If we would agree on
bindable_properties
being useful only when binding functions invoked, than we could fix it "on fly" when binding is happening, like so:I'm not sure that is the case though.
bindable_properties
is a public variable, it can be used for, say, gathering binding statistics (like here) and therefore deserves more consistency.It seems like If we are to stick with
bindable_properties
dictionary as it is, then we have to update it when copying happens.Maybe we should keep track of classes, where
bindableProperty
was ever used, and change the way that class is copied (for instance like was proposed in a workaround above). This might look something like this then:The text was updated successfully, but these errors were encountered: