[Tutor] What's the correct way to define/access methods of a member variable in a class pointing to an object?

Steven D'Aprano steve at pearwood.info
Sat Sep 3 13:17:36 EDT 2016


On Sat, Sep 03, 2016 at 02:51:22PM +0100, Alan Gauld via Tutor wrote:

[...]
> The first thing to do is point out that what you
> are asking about is the Law of Demeter on OOP.
> See Wikipedia for a full description. In essence
> it says that the user of an object should not
> directly access that object's internal attributes/state.
> So ideally you only access foo via a call to a method of
> Bar.


That's a very important answer too, thanks Alan for reminding me of it, 
but remember that the Law of Demeter is more of a guideline, and we 
should understand it, not just blindly quote it.

One classic example of the Law Of Demeter is:

"If you want your dog to come to you, don't talk to your dog's legs, 
talk to the dog."

class Dog:
    ...


fido = Dog()
# I want the dog to come here.
fido.left_front_leg.lift()
fido.left_front_leg.forward()
fido.left_front_leg.down()
fido.right_back_leg.lift()
...


Arggh, no, that's terrible! That violates the Law Of Demeter, and you 
shouldn't expect your users to do that. The caller shouldn't have to 
care about *how the dog walks*.

fido.command("come here boy!")

Or perhaps:

fido.heel()


whatever is most appropriate. The details of how the dog walks is 
encapsulated inside the Dog class.

Another classic example is of a transaction where the paper boy gives 
you a newspaper and you pay him a dollar:


newspaper = paperboy.get_paper()
paperboy.balance += 1.0
customer.trousers.wallet.balance -= 1.0


No! Would you really let the paperboy reach into your trousers, grab 
your wallet, open it up, and take money out? Again, another Demeter 
violation. Better to re-write your Customer class:

class Customer:
    def pay(self, amount):
        if amount > self.wallet.balance:
            raise ValueError
        self.wallet.balance -= amount
        return amount

paperboy.receive(customer.pay(1.0))


But sometimes the Law Of Demeter should not apply. Sometimes you are 
expected to tinker with the internals of an object.

car = Car()
# replace the engine with a bigger one
car.engine = Engine("800 horsepower of throbbing nitro-fueled POWER")
car.engine.inject(nitro=True)


but as I suggested in an earlier email, that mostly applies when the 
attribute is a fairly simple object like a list, a dict, or similar.




-- 
Steve


More information about the Tutor mailing list