In a large python project (openerp) I encounter several times the following pattern:
In a module, a class with its methods is defined. Then, in the same module and immediately after the class definition, an instance of the class is instantiated, that is then called from other modules.
# in module_A.py:
class ClassA(object):
def __init__(self, default="Hello world!"):
self.default = default
def my_method(self, data):
print self.default
print data
object_a = ClassA()
To me it looks simpler to define the methods as module functions, without the class lookup overload:
# in module_B.py:
default = "Hello world!"
def my_method(data):
print default
print data
Seen from other modules, the usage is very similar:
from module_a import object_a as prefix
prefix.my_method("I'm so objective!")
versus:
import module_b as prefix
prefix.my_method("I'm so modular!")
Is there any rationale to prefer pattern A over pattern B? Or is pattern B more pythonic?
Sometimes, you want different clients to be able to use your module with different settings in such a way that they don't conflict with each other. For example, Python's random
module provides a bunch of random number generation functions that are actually bound methods of a hidden Random
instance. Most users don't care too much what algorithm generates their random numbers or whether other modules asking for random numbers will change the sequence. However, users who do care can get their own Random
object and generate sequences of random numbers that won't be affected by other modules asking for random numbers.
Sometimes, something that's global now might not always be global. For example, if you're working on a planetary-scale RTS, you might have a Planet
class with one instance, because the battle only happens on one planet. However, you don't want to rule out the possibility of building something like Planetary Annihilation, with battles stretching across entire solar systems and dropping extinction-event asteroids as superweapons. If you get rid of the Planet
class and make its methods and attributes module-level, it'll be much harder to go back and add more planets later.
Sometimes, it's more readable to have objects doing things instead of modules. For example, suppose module joebob
defines two objects evil_overlord_bob
and good_guy_joe
.
class Bob(object):
def slaughter_everything(self):
print "Muahahaha! Die for my amusement!"
class Joe(object):
def stop_bob(self):
print "I won't let you hurt those innocents!"
evil_overlord_bob = Bob()
good_guy_joe = Joe()
Suppose Bob and Joe are very unique people. It's unthinkable that you'd want to create another object anything like Bob or Joe. In that case, you could move slaughter_everything
and stop_bob
to module-level and get rid of the Bob and Joe classes and objects entirely. However, then you'd be writing
joebob.slaughter_everything()
joebob.stop_bob()
It's much clearer what's going on if you can say
evil_overlord_bob.slaughter_everything()
good_guy_joe.stop_bob()
even if you'll never need to instantiate Bob's equally-evil twin brother greg_the_fleshripper
.