Posts: 544
Threads: 15
Joined: Oct 2016
Just want class object instance to update all children. Every time object value changes.
Linking class object instance attributes to class.
Can it be done any easier than this.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def set(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return str(vars(self))
class Dimension:
def __init__(self, w, h):
self.w = w
self.h = h
def set(self, w, y):
self.w = w
self.h = h
def __repr__(self):
return str(vars(self))
def dir_trim(item):
return [d for d in dir(item) if not d.startswith('__')]
class LinkProperty:
def __init__(self, attr):
self.attr = attr
def __set__(self, instance, value):
setattr(instance.read_value, self.attr, value)
instance.callback()
def __get__(self, instance, owner):
return getattr(instance.read_value, self.attr)
def link_variable(value, callback):
class LinkVariable:
def __init__(self, value, callback):
self.read_value = value
self.callback = callback
def __call__(self, value=None):
if value is None:
return self.read_value
self.read_value = value
self.callback()
def clear(self):
self.read_value = None
self.callback()
items = dir_trim(value)
for item in items:
setattr(LinkVariable, item, LinkProperty(item))
return LinkVariable(value, callback)
def callback():
print('Callback')
a = link_variable(Point(2,3), callback)
b = link_variable(Dimension(1,4), callback)
print(dir_trim(a))
print(dir_trim(b))
print(a.read_value, b.read_value)
a.x = 7
print(a.read_value, b.read_value)
print(a.x, a.y, b.w, b.h)
99 percent of computer problems exists between chair and keyboard.
Posts: 4,220
Threads: 97
Joined: Sep 2016
It's totally unclear to me what you are trying to do. Can you explain the desired behavior, in English, with examples?
Posts: 544
Threads: 15
Joined: Oct 2016
I have objects like a pygame.Rect. It has methods and properties.
Every time it values changes. I want a callback to update a list.
Example
The problem is I have to remember to type update_point_total.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def copy(self):
return Point(self.x, self.y)
def set(self, x, y):
self.x = x
self.y = y
def __add__(self, point):
return Point(self.x + point.x, self.y + point.y)
def __repr__(self):
return str(vars(self))
class MyObject:
def __init__(self, point):
self.parent = None
self.point = point
self.point_total = point.copy()
self.items = []
def add(self, my_object):
my_object.parent = self
my_object.update_point_total()
self.items.append(my_object)
def get_points(self):
if self.parent:
return self.point + self.parent.get_points()
return self.point.copy()
def update_point_total(self):
self.point_total = self.point.copy()
if self.parent:
self.point_total = self.get_points()
self.update_all_items()
def update_all_items(self):
for item in self.items:
item.update_point_total()
def __repr__(self):
return str(vars(self))
def main():
a = MyObject(Point(1,1))
b = MyObject(Point(2,2))
c = MyObject(Point(5,5))
d = MyObject(Point(10,10))
a.add(b)
c.add(d)
a.add(c)
print(a.point_total)
print(b.point_total)
print(c.point_total)
print(d.point_total)
# This is all over my code
b.point.x = 5
# If this is forgotten. Hard bug to find.
b.update_point_total()
c.point.y += 3
c.update_point_total()
print()
print(a.point_total)
print(b.point_total)
print(c.point_total)
print(d.point_total)
main() My solution was to use a class. That holds the rect and callback. I link this rect attributes, methods, and properties to the class.
For I don't have to remember to type update after value changes.
def dir_trim(item):
return [d for d in dir(item) if not d.startswith('__')]
class LinkProperty:
def __init__(self, attr):
self.attr = attr
def __set__(self, instance, value):
setattr(instance.read_value, self.attr, value)
instance.callback()
def __get__(self, instance, owner):
return getattr(instance.read_value, self.attr)
def link_variable(value, callback):
class LinkVariable:
def __init__(self, value, callback):
self.read_value = value
self.callback = callback
def __call__(self, value=None):
if value is None:
return self.read_value
self.read_value = value
self.callback()
def clear(self):
self.read_value = None
self.callback()
items = dir_trim(value)
for item in items:
setattr(LinkVariable, item, LinkProperty(item))
return LinkVariable(value, callback)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def copy(self):
return Point(self.x, self.y)
def set(self, x, y):
self.x = x
self.y = y
def __add__(self, point):
return Point(self.x + point.x, self.y + point.y)
def __repr__(self):
return str(vars(self))
class MyObject:
def __init__(self, point):
self.parent = None
self.point = link_variable(point, self.update_point_total)
self.point_total = point.copy()
self.items = []
def add(self, my_object):
my_object.parent = self
my_object.update_point_total()
self.items.append(my_object)
def get_points(self):
if self.parent:
return self.point.read_value + self.parent.get_points()
return self.point.copy()
def update_point_total(self):
self.point_total = self.point.copy()
if self.parent:
self.point_total = self.get_points()
self.update_all_items()
def update_all_items(self):
for item in self.items:
item.update_point_total()
def __repr__(self):
return str(vars(self))
def main():
a = MyObject(Point(1,1))
b = MyObject(Point(2,2))
c = MyObject(Point(5,5))
d = MyObject(Point(10,10))
a.add(b)
c.add(d)
a.add(c)
print(a.point_total)
print(b.point_total)
print(c.point_total)
print(d.point_total)
b.point.x = 5
c.point.y += 3
print()
print(a.point_total)
print(b.point_total)
print(c.point_total)
print(d.point_total)
main() Is there an easier or better way to tackle this ?
99 percent of computer problems exists between chair and keyboard.
Posts: 4,220
Threads: 97
Joined: Sep 2016
What about subclassing the Rect, and redoing all of it's attributes as standardized properties?
Posts: 4,784
Threads: 76
Joined: Jan 2018
Dec-03-2018, 03:00 PM
(This post was last modified: Dec-03-2018, 03:01 PM by Gribouillis.)
Windspar Wrote:Is there an easier or better way to tackle this ? Why not use the point member as a private member and define x and y properties in MyObject ?
class MyObject:
@property
def x(self):
return self._point.x
@x.setter
def x(self, value):
self._point.x = value
self.update_point_total()
...
b.x = 5
c.y += 3
Posts: 544
Threads: 15
Joined: Oct 2016
Dec-03-2018, 04:23 PM
(This post was last modified: Dec-03-2018, 04:23 PM by Windspar.)
@ Gribouillis. I would but Point is just an example. I would have to do that for every method that could change it value.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def set(self, x, y):
self.x = x
self.y = y
def move(self, x, y):
self.x += x
self.y += y
# some other properties Figure out how to do it with __setattr__ and __getattr__.
class LinkObject:
def __init__(self, value, callback):
self.read_value = value
self.callback = callback
def __call__(self, value=None):
if value is None:
return self.read_value
self.read_value = value
self.callback()
def __setattr__(self, instance, value):
if instance in ['read_value', 'callback']:
super().__setattr__(instance, value)
else:
setattr(self.read_value, instance, value)
self.callback()
def __getattr__(self, instance):
return getattr(self.read_value, instance)
def clear(self):
self.read_value = None
self.callback = callback Edit. Fix __call__
99 percent of computer problems exists between chair and keyboard.
Posts: 4,784
Threads: 76
Joined: Jan 2018
Dec-03-2018, 04:31 PM
(This post was last modified: Dec-03-2018, 04:32 PM by Gribouillis.)
The solution seems to me way too complicated, but perhaps I don't understand exactly what you want to do. Do you need to call update_point_total() in other situations than when x or y changes?
Posts: 544
Threads: 15
Joined: Oct 2016
The read_only/private way. Will not let methods and properties to be use.
In these method and properties update would need to be called.
I have pygame.Rect like object. That has 7 methods,
4 attributes, and 18 properties that can change data.
I like to have access to these method and properties.
99 percent of computer problems exists between chair and keyboard.
|