14

I want to make a single database object available across many python modules.

For a related example, I create globl.py:

DOCS_ROOT="c:\docs" ## as an example
SOLR_BASE="http://localhost:8636/solr/"

Any other module which needs it can do a

from globl import DOCS_ROOT

Now this example aside, I want to do the same thing with database connection objects, share them across many modules.

import MySQLdb
conn = MySQLdb.connect (host="localhost"...)
cursor = conn.cursor()

I tried this on the interpreter:

from globl import cursor

and it seems to work. But I suspect that this will cause the same module to be executed each time one imports from it. So is this the proper way?

3 Answers 3

51

Even if the import doesn't run the code multiple times, this is definitely not the correct way.

You should instead hide the process of obtaining a connection or cursor behind a function. You can then implement this function using either a Singleton or Object Pool design pattern.

So it would be something like this:

db.py:

_connection = None

def get_connection():
    global _connection
    if not _connection:
        _connection = MySQLdb.connect(host="localhost"...)
    return _connection

# List of stuff accessible to importers of this module. Just in case
__all__ = [ 'getConnection' ]

## Edit: actually you can still refer to db._connection
##         if you know that's the name of the variable.
## It's just left out from enumeration if you inspect the module

someothermodule.py:

import db
conn = db.get_connection() # This will always return the same object

By the way, depending on what you are doing, it may not be so much of a good idea to share your connection object rather than create a new one every time you need one.

But, that's why you'd want to write a get_connection() method, to abstract from these issues in the rest of your code.

Sign up to request clarification or add additional context in comments.

5 Comments

Great answer, this too. I would have chosen this one as this is teaches something new.
If i run this code I get UnboundLocalError: local variable '_connection' referenced before assignment
@Jim That's true. It was a rushed example. I've added a line with global _connection.
using __all__ also has the nice feature of representing the things that'll be imported into your namespace using import *. not that you should ever use import * if you can help it! :-)
I suspect it is a typo: in the __all__ array you used camel case to write the function name, but the function is written in snake case.
5

You suspect wrongly. The code will only be executed once - subsequent imports just refer to the module via sys.modules, and don't re-run it.

(Note that this is the case as long as you always use the same path to import the module - if you do from globl import cursor in one place, and from my.fullyqualified.project.global import cursor in another, you probably will find the code is re-executed.)

Edit to add as S.Lott says in the comment, this is a perfectly good way to handle a global object.

1 Comment

What about "is this the proper way?" I think that you should point out that a module global like this works out pretty well in the long run.
1

I think Daniel already answered the question, while I'd like to add few comments about the cursor object you want to share.

It is generally not a good idea to share the cursor object that way. Certainly it depends on what your program is, but as a general solution I'd recommend you to hide this cursor object behind a "factory" producing cursors. Basically you can create a method cursor() or get_cursor() instead of making the cursor a global variable. The major benefit (but not the only one) - you can hide a more complex logic behind this "factory" - pooling, automatic re-connection in case the connection is dropped, etc. Even if you don't need it right away - it will be very easy to add it later if you start using this approach now, and while for now you can keep this function implementation as simple as return _cursor.

And yes, still, the module itself will be imported once only.

1 Comment

I will refer this in future. Its a fine way of making complex stuff behind a simple interface.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.