@@ -18,21 +18,41 @@ class _Obs(Generic[P]):
18
18
def __init__ (self , value : P ):
19
19
self .value = value
20
20
# This will keep any added listener even if it is not referenced anymore and would be garbage collected
21
- self .listeners : Set [Callable [[], Any ]] = set ()
21
+ self .listeners : Set [Callable [[Any , P ], Any ]] = set ()
22
22
23
23
24
24
class Property (Generic [P ]):
25
25
"""
26
26
An observable property which triggers observers when changed.
27
27
28
+ .. code-block:: python
29
+
30
+ def log_change(instance, value):
31
+ print("Something changed")
32
+
33
+ class MyObject:
34
+ name = Property()
35
+
36
+ my_obj = MyObject()
37
+ bind(my_obj, "name", log_change)
38
+ unbind(my_obj, "name", log_change)
39
+
40
+ my_obj.name = "Hans"
41
+ # > Something changed
42
+
28
43
:param default: Default value which is returned, if no value set before
29
44
:param default_factory: A callable which returns the default value.
30
45
Will be called with the property and the instance
31
46
"""
47
+
32
48
__slots__ = ("name" , "default_factory" , "obs" )
33
49
name : str
34
50
35
- def __init__ (self , default : Optional [P ] = None , default_factory : Optional [Callable [[Any , Any ], P ]] = None ):
51
+ def __init__ (
52
+ self ,
53
+ default : Optional [P ] = None ,
54
+ default_factory : Optional [Callable [[Any , Any ], P ]] = None ,
55
+ ):
36
56
if default_factory is None :
37
57
default_factory = lambda prop , instance : cast (P , default )
38
58
@@ -60,7 +80,11 @@ def dispatch(self, instance, value):
60
80
obs = self ._get_obs (instance )
61
81
for listener in obs .listeners :
62
82
try :
63
- listener ()
83
+ try :
84
+ listener (instance , value )
85
+ except TypeError :
86
+ # If the listener does not accept arguments, we call it without it
87
+ listener () # type: ignore
64
88
except Exception :
65
89
print (
66
90
f"Change listener for { instance } .{ self .name } = { value } raised an exception!" ,
@@ -95,8 +119,8 @@ def bind(instance, property: str, callback):
95
119
Binds a function to the change event of the property. A reference to the function will be kept,
96
120
so that it will be still invoked, even if it would normally have been garbage collected.
97
121
98
- def log_change():
99
- print("Something changed")
122
+ def log_change(instance, value ):
123
+ print(f"Value of {instance} changed to {value} ")
100
124
101
125
class MyObject:
102
126
name = Property()
@@ -105,7 +129,7 @@ class MyObject:
105
129
bind(my_obj, "name", log_change)
106
130
107
131
my_obj.name = "Hans"
108
- # > Something changed
132
+ # > Value of <__main__.MyObject ...> changed to Hans
109
133
110
134
:param instance: Instance owning the property
111
135
:param property: Name of the property
@@ -122,7 +146,7 @@ def unbind(instance, property: str, callback):
122
146
"""
123
147
Unbinds a function from the change event of the property.
124
148
125
- def log_change():
149
+ def log_change(instance, value ):
126
150
print("Something changed")
127
151
128
152
class MyObject:
@@ -150,10 +174,7 @@ class MyObject:
150
174
class _ObservableDict (dict ):
151
175
"""Internal class to observe changes inside a native python dict."""
152
176
153
- __slots__ = (
154
- "prop" ,
155
- "obj"
156
- )
177
+ __slots__ = ("prop" , "obj" )
157
178
158
179
def __init__ (self , prop : Property , instance , * largs ):
159
180
self .prop : Property = prop
@@ -211,10 +232,7 @@ def set(self, instance, value: dict):
211
232
class _ObservableList (list ):
212
233
"""Internal class to observe changes inside a native python list."""
213
234
214
- __slots__ = (
215
- "prop" ,
216
- "obj"
217
- )
235
+ __slots__ = ("prop" , "obj" )
218
236
219
237
def __init__ (self , prop : Property , instance , * largs ):
220
238
self .prop : Property = prop
0 commit comments