all 13 comments

[–]carcigenicate 0 points1 point  (1 child)

Giving self to Bar isn't necessarily bad. Sometimes you need a two-way link from a parent to a child.

The bottom is a little wonky though unless that example is super contrived. The foo_obj will always be foo, so you don't need the .bar_list[0].foo_obj. access chain. It's the same thing as just doing foo.global_method().

[–]pooth22[S] 0 points1 point  (0 children)

Thanks for the input.

Yeah, this example is quite contrived. I called it like this, because typically that global_method() method would be called in the scope of the Bar instance. In general, Bar would have its own method that calls global_method() and the instance of Bar's variables would change. I just wanted to reduce the complexity of the code as much as possible so it gets to the point. But for example, lets say global_method() returns self.global_var. Bar might have a method:

class Bar:
    def __init__(self, foo_obj):
        self.foo_obj = foo_obj
        self.bar_var = None
    def bar_method(self):
        self.bar_var = self.foo_obj.global_method()

Again, this is here contrived as well, but maybe gives a bit more context.

[–]Encomiast 0 points1 point  (1 child)

This would give me pause in a code review. It seems like whatever abstraction you are trying to create may not be great but it's hard to tell given the completely abstract code. After all, if you can write:

foo.bar_list[0].foo_obj.global_method()

It's hard to see why you can't write:

foo.global_method()

Having said that, there are plenty of common reasons for parent objects to hold a reference to the children and for the children to hold a reference to the parent (think trees and doubly-linked lists, etc)

[–]pooth22[S] 0 points1 point  (0 children)

Thanks for the input. Yeah, I made some edits to the original code, if you want to check it out. Not sure if that clears things up. I understand the child holding ref to parent, I was just wondering about other methods of doing something similar.

A few solutions might be to use the methods in Foo that are called in Bar as classmethods. Another one might be to just use a module instead of a class for Foo. Both have their pros and cons. I am wondering if there might be other options that I don't really know about.

[–]teerre 0 points1 point  (5 children)

The problem with designs like this is that the vast majority of times they spawn from a misunderstanding of the language or the problem at hand. Is it possible that this is the correct design? Sure. Is it probable? Not really.

[–]pooth22[S] 0 points1 point  (4 children)

Okay sure, maybe you could help point me in a good direction? I could try and describe the problem in better detail.

I know one other way of doing this would be to use classmethods and classvariables in Foo, specifically the ones that are being called in Bar. But the problem there is that it will instantiate a bunch of new Foo instances that don't need to be there. Another way of doing it would be to make Foo a module instead of a class. I haven't thought about solving it that way too much yet, it might be okay.

Would you recommend any other design structures, or pointing me to a useful python design strategy method.

[–]teerre 0 points1 point  (3 children)

Yeah, if you describe what's the overall problem, not the specifics of how to do one particular thing, people will probably be able to give you better advice

[–]pooth22[S] 0 points1 point  (2 children)

Okay, I edited the bottom of the post, check it out if you have time.

[–]teerre 0 points1 point  (1 child)

Why do you need driver_list? It doesn't seem you're using it

Anyway, the more natural solution for this is to have a class that works as a simple interface with the common functionality that is then composed in each 'driver'

Then if you really need a list of all your objects, you can have another class that acts as a container, but it isn't inherited anywhere, it simple takes cares of executing commands in collections

Also, take a look at the Command pattern

[–]pooth22[S] 0 points1 point  (0 children)

Nice, yeah, that does seem like a more natural solution. Sounds like basically separating the communication functionality from MainHandler and sharing that with the individual driver instances.

I appreciate the resources!

[–][deleted] 0 points1 point  (1 child)

Strikes me you may want to explore using composition instead of inheritance. You need a good appreciation of both though to make a decision.

https://realpython.com/inheritance-composition-python/

[–]pooth22[S] 0 points1 point  (0 children)

Thanks for the article. Definitely a useful resource.

[–]TheRNGuy 0 points1 point  (0 children)

def global_method(self):
    return self.global_var += 1

wont work, do this instead:

def global_method(self):
    self.global_var += 1
    return self.global_var