Python Forum
Class object instance. Link instance attribute to class. Can it be done easier.
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Class object instance. Link instance attribute to class. Can it be done easier.
#1
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.
Reply
#2
It's totally unclear to me what you are trying to do. Can you explain the desired behavior, in English, with examples?
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#3
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.
Reply
#4
What about subclassing the Rect, and redoing all of it's attributes as standardized properties?
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#5
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
Reply
#6
@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.
Reply
#7
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?
Reply
#8
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.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  class and runtime akbarza 4 211 Mar-16-2024, 01:32 PM
Last Post: deanhystad
  Operation result class SirDonkey 6 393 Feb-25-2024, 10:53 AM
Last Post: Gribouillis
  The function of double underscore back and front in a class function name? Pedroski55 9 526 Feb-19-2024, 03:51 PM
Last Post: deanhystad
  super() and order of running method in class inheritance akbarza 7 580 Feb-04-2024, 09:35 AM
Last Post: Gribouillis
  Class test : good way to split methods into several files paul18fr 4 380 Jan-30-2024, 11:46 AM
Last Post: Pedroski55
  Good class design - with a Snake game as an example bear 1 1,703 Jan-24-2024, 08:36 AM
Last Post: annakenna
  question about __repr__ in a class akbarza 4 505 Jan-12-2024, 11:22 AM
Last Post: DeaD_EyE
  error in class: TypeError: 'str' object is not callable akbarza 2 418 Dec-30-2023, 04:35 PM
Last Post: deanhystad
  super() in class akbarza 1 386 Dec-19-2023, 12:55 PM
Last Post: menator01
  error occuring in definition a class akbarza 3 599 Nov-26-2023, 09:28 AM
Last Post: Yoriz

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020