0

In ruby it is conventional to define a class inside the file of the same name. Nesting can be done by making a folder of the same name as the file.

+--lib
   +--broccoli.rb
   +--broccoli/
      +--broccoli_powers.rb
      +--broccoli_powers/
        +--green.rb

I'm relatively new to python, so I'm trying to figure out how to generate the equivalent structure in python (but I want it to be "pythonic"). The main reason things can't be structured the same as in ruby is that you cannot have a module and package with the same name:

this won't work -- no way to get at broccoli.py and broccoli:

+--lib
   +--broccoli.py
   +--broccoli/
      +--broccoli_powers.py

One way around this is to define an eponymous class in the __init__.py of the folder:

+--lib
   +--broccoli/
      +--__init__.py  # <- define "class Broccoli" here
      +--broccoli_powers.py

Now, I can use the Broccoli class like this:

from broccoli import Broccoli

And I could get at the BroccoliPowers class like this:

from broccoli.broccoli_powers import BroccoliPowers

But if I want to go deeper into the broccoli_powers namespace then I would need to move broccoli_powers.py into the __init__.py of the broccoli_powers folder like this:

+--lib
   +--broccoli/
      +--__init__.py   # <- class Broccoli
      +--broccoli_powers/
          +--__init__.py   # <- class BroccoliPowers
          +--green.py

That's not as bad as it seems because the BroccoliPowers class is still accessible with the exact same invocation as before: "from broccoli.broccoli_powers import BroccoliPowers".

I don't like tucking substantial amounts of code into __init__.py files, but it is natural for me to organize my code into classes, and it seems natural to nest classes. What is the "pythonic" way to do this?

An alternative approach that I've considered for when I want to nest is moving the class definition to some file (say "cls.py" or "klass.py") and importing that in the __init__.py file namespace, like this:

+--lib
   +--broccoli/
      +--__init__.py  # <- "from cls import Broccoli" 
      +--cls.py       # <- define "class Broccoli" here
      +--broccoli_powers.py

That achieves the same effect (I can access the Broccoli class as expected: "from broccoli import Broccoli") and I am not putting substantial amounts of code inside the __init__.py file.

What is the pythonic way to nest in this fashion? What am I missing?

bwv549
  • 5,243
  • 2
  • 23
  • 20

1 Answers1

2

First of all, you should consider that classes are much less of a requirement in Python than they are in Ruby. All code does not need to be in a class; you should reserve those for when you need to encapsulate state. Standalone functions can live perfectly happily at module level.

The other thing to bear in mind is one of the elements of the Zen of Python (do import this in the shell if you haven't seen it): Flat is better than nested. That is, it is not common to nest code deeply, and you might want to reconsider your structure.

Now, bearing both of those in mind, I would say that your final option is the most Pythonic here: define your class in a separate module, and import it into __init__.py.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Thank you for that great answer. Just a minor point of clarification: the answer implied that all ruby code must be in a class, but that is not the case (even if it is more the convention in ruby) – bwv549 Sep 30 '14 at 18:01