Python trick - how to invoke method in owner class

Sometimes “property” class need to call a method in it’s “owner” class.

You can achieve it by passing owner instance to the __ init __ method of property, something like this:

class Leg():
    def __init__(self, owner):
        self.owner = owner
    
    def move(self):
        self.owner.jump()
    
class Dog():

    def __init__(self):
        self.front_left = Leg(owner=self)
        
    def jump(self):
        print("jumping")
    
d = Dog()
d.front_left.move()

… so later, when move() method is invoked, it can call owners’s jump method.

However, this is pretty ugly coding style, isn’t it ?

Trick with __ get __

You can achieve the same behavior by more elegant method, avoiding passing owner’s instance to constructor.

I added some print() functions and comments to illustrate the behavior, so code seems longer, but in fact it isn’t.

class Leg():

    def __init__(self):
        self.owner = None

    def __get__(self, instance, owner):
        # This is called, when something like dog().front_left ... is evaluated
        # Now Leg knows where it belongs to, so save the owner's instance for later use
        if instance:
            self.owner = instance
        # this line is obligatory to __get__ function work properly:
        return self
    
    def move(self):
        # Thats just an ordinary function, so do some stuff:
        print("...leg is moving")
        
        # but because of leg may know its owner, make some magic :-)
        if self.owner:
            print("...and, because of leg knows its owner:")
            self.owner.jump()
        else:
            print("...and there is no owner, so that's all.")


class Dog():

    front_left = Leg()
    rear_left = Leg()
    front_right = Leg()
    rear_right = Leg()
    
    def jump(self):
        print('.. dog is jumping!')

print("Move single leg:")
l = Leg()
l.move()

print("\nMove leg, attached to dog:")
d = Dog()
d.front_left.move()

Další posty: