I believe that readability and the KISS principle are the most important things in programming. That's why I use Python :)
And here is exact situation, which I encounter very often:
Say, I have a nice and clean script, which is a wrapper for database handling:
import database_schema as schema
loader = schema.Loader("sqlite:///var/database.db")
session = loader.session
def addUser(name, full_name, password):
user = schema.User(name, full_name, password)
session.add(user)
session.commit()
def listUsers():
all_users = session.query(schema.User).all()
return all_users
Which is used like this:
import database
database.addUser("mike", "Mike Driscoll", "password")
database.listUsers()
At some point, I want to rewrite that module, so that it can work with databases on different path (for unit testing, for instance).
So, what are my options?
The most intuitive thing is to add database_path == ""
variable, and then... what? Setting it with setPath(new_path)
function, and then adding exception (if database_path == "": raise SomeException
) to every single function, is just ugly and shouldn't be done by anyone.
Full featured class, with setting the self._database_path
at initialization time.
Which is then used this way:
from database import Database
database = Database("sqlite:///var/database.db")
database.addUser("mike", "Mike Driscoll", "password")
database.listUsers()
This is already more lines of code than in the first example, and addition of the naming problem: having a class called Database
in the module database
is kind of dumb, no?
Sorry for the long read, here my final questions:
__init__
functions for modules, in Python?P.S. sorry for my English.
Edit:
So, to make this clear, how this code may look like in my imaginative Python universe:
import database_schema as schema
def __init__(database_path):
loader = schema.Loader(database_path)
global session
session = loader.session
def addUser(name, full_name, password):
user = schema.User(name, full_name, password)
session.add(user)
session.commit()
def listUsers():
all_users = session.query(schema.User).all()
return all_users
And used like this:
import database("sqlite:///var/database.db")
database.addUser("mike", "Mike Driscoll", "password")
database.listUsers()
A module is a Python object with arbitrarily named attributes that you can bind and reference. The Python code for a module named mod normally resides in a file named mod.py. When you try to import it, a new namespace is created that contains all the attributes of that module.
Though all said, it is not the same as class and creation of object instances of that class. These are different abstractions and should be used as such.
instead of testing for
if database_path == "":
....
do it pythonic way
if database_path:
....
And rather than raising exception, you could use assert
assert database_path != "", 'database path empty'
A module does not exist in flavors like object instances of class does. Importing a module will create a namespace with the same set of attributes every time you import it. In such situation, init may not make much sense.
There is nothing wrong with the second form of code you have provided. and you if you do not want to do that them some of the above idioms may ease your pain :)
For this type of situations, I use the optional parameter.
def addUser(name, full_name, password, _loader=None):
user = schema.User(name, full_name, password)
if (_loader is None):
# Use global values.
session.add(user)
session.commit()
else:
_session = _loader.session
# ...
I, myself, stay away from initializing stuffs like this at module loading. Imagine you want to create documentation with tools like epydoc
. It makes no sense to create a connection in that context just because epydoc
loads the module. I would definitely go with the class approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With