Accessing attributes of an object A from another object B itself attribute of A

Viewed 139

I'm working around a physical problem, involving a collection of (physical) objects (let's call them B) an their relation to another (physical) object (let's call it A). Each B has individual properties, and the computation of these properties may depend on A's properties. A is unique and disconnected from A, the Bs have no purpose or meaning. Is there a way to access, from the class definition of B, the attributes of A which would be on the same "level" if an object B was to be instantiated from an instance of A? Something like

class A(object):
    def __init__(self, foo, bar, b1, b2):
        self.foo = foo
        self.bar = bar
        self.list_bs = [b1, b2]  # instances of B

class B(object):
    def computation(self):
        # something involving foo or bar, magically accessed

I feel like I have four options (... are for brevity and not the Python ellipsis):

  1. passing my instance of A to the constructor of B
    class A(object):
        def add(self, b):
            self.list_bs.append(b)
    
    class B(object):
        __init__(self, a, ...):
            self.a = a
            ...
            ...
    
        def compute1(self):
            # something involving self.a.foo
    
        def compute2(self):
            # something involving self.a.bar
    
    a = A()
    a.add(B(a, ...))
    a.add(B(a, ...))
    
  2. passing selected attributes of my instance of A to the constructor of B
    class A(object):
        def add(self, b):
            self.list_bs.append(b)
    
    class B(object):
        def __init__(self, a1, a2, ...):
            self.foo = a1
            self.bar = a2
            ...
            ...
    
        def compute1(self):
            # something involving self.foo
    
        def compute2(self):
            # something involving self.bar
    a = A()
    a.add(B(a.foo, a.bar, ...))
    a.add(B(a.foo, a.bar, ...))
    
  3. triggering all computation requesting A's attributes from A, even if they are more related to B
    def class A(object):
        def add(self, b):
            b.compute1(self.foo)
            b.compute2(self.bar)
            self.list_bs.append(b)
    
    class B(object):
        def compute1(self, a1):
            # something involving a1
    
        def compute2(self, a2):
            # something involving a2
    
  4. ditching A and using its attributes as class attributes for B
    class B:
        foo = a1
        bar = a2
    
        def compute1(self):
            # something involving B.foo
    
        def compute2(self):
            # something involving B.bar
    

Am I missing something else, or over thinking this? Which one of these options would be the lightest/quickest? Options 1 and 2 feel like a lot of duplicating, even if it's only references. Option 3 feels like it could be hard to maintain. Option 4 would make me merge some methods of A with nothing to do with B into B, so I'm not a big fan.

1 Answers

I sometimes prefer to separate logic from data container (I'm not claiming that's the faster way neither the better), especially when it comes down to opertate on different variables/istances. In this case I thik I would consider to use 3 classes instead of one so the data stay separate from the logic. If the data you are handling is simple this may be and overshot, but, apart on that:

class A(object):
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar
        

class B(object):
    def __init__(self, ):
        # whatever_you need

# optionally, if you really like classes, 
# you can also think about wrapping the list in his own class:
class WrapperB():
    def __init__(self):
      self.b_list = []

    def add(b: B):
       self.b_list.append(b)

class BusinessLogic()
    @staticmethod
    def compute(foo, bar, b_list: WrapperB or list):
       # whatever you need

Suppose you don't have just 2 classis (A, and B), but a lot more: I think logic separation can be an option to consider.

EDIT: As pointed out, a class with a single static method it's not really a "class" (in the sense that you don't need to build a class for a single staticmethod). In this case you can consider implementing a simple function. In this example I used a class just because if you need something more from the logic you can expand it.

Related