I have a method in my Python code that returns a tuple - a row from a SQL query. Let's say it has three fields: (jobId, label, username)
For ease of passing it around between functions, I've been passing the entire tuple as a variable called 'job'. Eventually, however, I want to get at the bits, so I've been using code like this: (jobId, label, username) = job
I've realised, however, that this is a maintenance nightmare, because now I can never add new fields to the result set without breaking all of my existing code. How should I have written this?
Here are my two best guesses: (jobId, label, username) = (job[0], job[1], job[2]) ...but that doesn't scale nicely when you have 15...20 fields
or to convert the results from the SQL query to a dictionary straight away and pass that around (I don't have control over the fact that it starts life as a tuple, that's fixed for me)
-
I'd say that a dictionary is definitely the best way to do it. It's easily extensible, allows you to give each value a sensible name, and Python has a lot of built-in language features for using and manipulating dictionaries. If you need to add more fields later, all you need to change is the code that converts the tuple to a dictionary and the code that actually makes use of the new values.
For example:
job={} job['jobid'], job['label'], job['username']=<querycode>Jay : see also http://code.activestate.com/recipes/81252/From Chris Upchurch -
With a tuple it will always be a hassle to add or change fields. You're right that a dictionary will be much better.
If you want something with slightly friendlier syntax you might want to take a look at the answers this question about a simple 'struct-like' object. That way you can pass around an object, say
job, and access its fields even more easily than a tuple or dict:job.jobId, job.username = jobId, usernameFrom dF -
Perhaps this is overkill for your case, but I would be tempted to create a "Job" class that takes the tuple as its constructor argument and has respective properties on it. I'd then pass instances of this class around instead.
From Ryan Duffield -
I would use a dictionary. You can convert the tuple to a dictionary this way:
values = <querycode> keys = ["jobid", "label", "username"] job = dict([[keys[i], values [i]] for i in xrange(len(values ))])This will first create an array [["jobid", val1], ["label", val2], ["username", val3]] and then convert that to a dictionary. If the result order or count changes, you just need to change the list of keys to match the new result.
PS still fresh on Python myself, so there might be better ways off doing this.
Daniel Goldberg : See Aaron Maenpaa answer of Zip. A common newbie mistake in Python is using list comprehension when zip will suffice.From Staale -
How about this:
class TypedTuple: def __init__(self, fieldlist, items): self.fieldlist = fieldlist self.items = items def __getattr__(self, field): return self.items[self.fieldlist.index(field)]You could then do:
j = TypedTuple(["jobid", "label", "username"], job) print j.jobidIt should be easy to swap
self.fieldlist.index(field)with a dictionary lookup later on... just edit your__init__method! Something like Staale does.From Daren Thomas -
@Staale
There is a better way:
job = dict(zip(keys, values))Daniel Goldberg : This is also very maintainable code, the only "problem" is rebuilding the code to deal with dictionaries.From Aaron Maenpaa -
An old question, but since no one mentioned it I'll add this from the Python Cookbook:
Recipe 81252: Using dtuple for Flexible Query Result Access
This recipe is specifically designed for dealing with database results, and the dtuple solution allows you to access the results by name OR index number. This avoids having to access everything by subscript which is very difficult to maintain, as noted in your question.
From Jay -
This is an old question, but...
I'd suggest using a named tuple in this situation: collections.namedtuple
This is the part, in particular, that you'd find useful:
Subclassing is not useful for adding new, stored fields. Instead, simply create a new named tuple type from the _fields attribute.
From JAB -
If you're using the MySQLdb package, you can set up your cursor objects to return dicts instead of tuples.
import MySQLdb, MySQLdb.cursors conn = MySQLdb.connect(..., cursorclass=MySQLdb.cursors.DictCursor) cur = conn.cursor() # a DictCursor cur2 = conn.cursor(cursorclass=MySQLdb.cursors.Cursor) # a "normal" tuple cursorFrom jpkotta
0 comments:
Post a Comment