Python Worst Practices

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Feb 26 07:26:15 EST 2015


Chris Angelico wrote:

> On Thu, Feb 26, 2015 at 10:54 AM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> - Violating the Rule of Demeter: don't talk to the dog's leg, talk to
>>   the dog. Or another way to put it: don't let the paper boy reach
>>   into your pocket for money.
> 
> I'd call that code smell, rather than an automatic worst practice.


Well, I did end my post with:


And very possibly the worst practice of all:

- Failing to understand when it is, and isn't, appropriate to break
  the rules and do what would otherwise be a bad practice.


:-)


> Suppose this:
> 
> class Shelf:
>     def __init__(self):
>         self.items = [] # Empty shelf
> 
> bookshelf = Shelf()
> bookshelf.items.append(book)
> 
> To enforce Demeter, you'd have to add a bunch of methods to the Shelf
> whose sole purpose is to pass word along to the items list. Sure, it
> makes some design sense to say "Add this book to the shelf" rather
> than "Add this book to the items on the shelf", but all those lines of
> code are potential bugs, and if you have to reimplement huge slabs of
> functionality, that too is code smell. So there are times when it's
> correct to reach into another object.

Yes, well this comes down to the question of encapsulation and
information-hiding. The advantage of exposing the list of items to the
public is that anyone can add or remove items, sort them, reverse them,
etc. The disadvantage is that you are now committed to keeping that list as
part of the public API and you can't easily change the implementation.

In this specific example, I'd probably keep the list as part of the Shelf
API, although I'd be tempted to make self.items a read-only property. That
will allow you to call list mutator methods, but prevent you from doing
something silly like:

bookshelf.items = 23


> But the times to use two dots are much rarer than the times to use one
> dot (the paper boy shouldn't reach into your pocket for money, but
> ThinkGeek has your credit card number on file so you can order more
> conveniently), and I can't think of any example off-hand where you
> would want more than three dots.

The Law of Demeter is not really about counting dots. Ruby encourages
chaining methods. Python doesn't, since built-ins typically don't return
self. But in your own classes, you can have methods return self so you can
chain them like this:

mylist.append(spam).insert(1, eggs).append(cheese).sort().index(ham)

Five dots or not, this is not a violation of Demeter. Likewise for long
package names:

from mylibrary.audiovisual.image.jpeg import Handler


The Law of Demeter is more about information hiding. Clearly you don't hide
*public* attributes of your class, otherwise they aren't public, so it's
perfectly acceptable to say:

myshelf.items.append(spam).insert(1, eggs).append(cheese).sort().index(ham)

if items is public. But if the Shelf designer decides that the user
shouldn't know anything about how the shelf stores its items, then the
*first* dot violates the Law of Demeter.



-- 
Steven




More information about the Python-list mailing list