Python getters and setters

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Aug 17 19:40:30 EDT 2013


On Sun, 18 Aug 2013 00:52:06 +0200, Irmen de Jong wrote:

> On 17-8-2013 19:18, Steven D'Aprano wrote:
[...]
>> How is this:
>> 
>> obj.data_length()
>> 
>> easier for the user than this?
>> 
>> len(obj.data)
>> 
>> 
> It's not easier for the user perse, but it might be preferable from a
> design point of view. For the direct components of obj, it's probably
> alright to access them directly. 

Yes, and my comments assume that obj.data is public in the first place.


> There's something called the Law of
> Demeter aka principle of least knowledge
> (http://en.wikipedia.org/wiki/Law_of_Demeter) though. It basically
> argues against the use of "more than one dot". Doing that ties the use
> of the object more to the actual implementation/internal structure of
> the object.

A very good point! But not an easy one to understand. The Law of Demeter 
can be described as "if you want to walk the dog, talk to the dog, not 
the dog's legs". Another classic example is of the paperboy who reaches 
into your back pocket, pulls out your wallet, removes the money he is 
owed, then puts your wallet back:

# No, this is bad design.
class Paperboy:
    def take_payment(self, customer):
        payment_owed = 2
        wallet = customer.backpocket.get_wallet()
        money = wallet.take(payment_owed)
        self.money += money
        customer.backpocket.put_wallet(wallet)


It's bad design because it ties the paperboy to one specific 
implementation of customer. Perhaps the customer carries his wallet in a 
front pocket. Or she carries her purse in her handbag. Or she is the 
Queen of England, and doesn't carry money at all, but has a flunky who 
carries money for her. Better is:

class Paperboy:
    def take_payment(self, customer):
        payment_owed = 2
        self.money = customer.get_payment(payment_owed)

and raise an error if the customer doesn't implement get_payment.


The Law of Demeter is often characterised as "don't use more than one dot 
at a time", but of course that's wrong for two reasons:


- Re-writing take_payment to avoid multiple dots is still wrong:


    def take_payment(self, customer):
        payment_owed = 2
        pocket = customer.backpocket
        wallet = pocket.get_wallet()
        money = wallet.take(payment_owed)
        self.money += money
        pocket.put_wallet(wallet)


- If the attribute is part of the public interface, then it is okay to 
use it no matter how deep (how many dots) it is.

The Law of Demeter is really about being careful about what interface 
your classes provide. Customers should provide a get_payment method; dogs 
should provide a walk method. You shouldn't have to send individual step 
messages to the dog's legs.


-- 
Steven



More information about the Python-list mailing list