Разделение кортежей в Python - лучшая практика?
Вопрос
У меня есть метод в моем коде Python, который возвращает кортеж - строку из SQL-запроса.Допустим, у него есть три поля:(JobID, метка, имя пользователя)
Для удобства передачи его между функциями я передавал весь кортеж как переменную с именем 'job'.В конце концов, однако, я хочу добраться до сути, поэтому я использую такой код:(JobID, метка, имя пользователя) = задание
Однако я понял, что это кошмар обслуживания, потому что теперь я никогда не смогу добавить новые поля в результирующий набор, не нарушив весь мой существующий код.Как я должен был это написать?
Вот мои два лучших предположения:(JobID, label, username) = (задание [0], задание [1], задание [2]) ... но это не очень хорошо масштабируется, когда у вас 15 ... 20 полей
или сразу преобразовать результаты SQL-запроса в словарь и передать это по кругу (я не контролирую тот факт, что он начинает свою жизнь как кортеж, для меня это исправлено)
Решение
Я бы сказал, что словарь, безусловно, лучший способ сделать это.Он легко расширяем, позволяет присвоить каждому значению разумное имя, а Python обладает множеством встроенных языковых функций для использования словарей и манипулирования ими.Если вам понадобится добавить дополнительные поля позже, все, что вам нужно изменить, - это код, который преобразует кортеж в словарь, и код, который фактически использует новые значения.
Например:
job={}
job['jobid'], job['label'], job['username']=<querycode>
Другие советы
@Стаале
Есть способ получше:
job = dict(zip(keys, values))
Это старый вопрос, но...
Я бы предложил использовать именованный кортеж в этой ситуации: сборники.namedtuple
Это та часть, в частности, которая показалась бы вам полезной:
Создание подклассов бесполезно для добавления новых сохраненных полей.Вместо этого просто создайте новый именованный тип кортежа из атрибута _fields.
Возможно, это излишне для вашего случая, но у меня возникло бы искушение создать класс "Job", который принимает кортеж в качестве аргумента конструктора и имеет для него соответствующие свойства.Затем я бы вместо этого передал экземпляры этого класса другим пользователям.
Я бы воспользовался словарем.Вы можете преобразовать кортеж в словарь следующим образом:
values = <querycode>
keys = ["jobid", "label", "username"]
job = dict([[keys[i], values [i]] for i in xrange(len(values ))])
Сначала будет создан массив [["jobid", val1], ["label", val2], ["username", val3]], а затем преобразован в словарь.Если порядок результатов или количество изменятся, вам просто нужно изменить список ключей, чтобы они соответствовали новому результату.
PS я сам все еще новичок в Python, так что, возможно, есть способы получше сделать это.
Старый вопрос, но поскольку никто не упоминал об этом, я добавлю это из поваренной книги Python:
Рецепт 81252:Использование dtuple для гибкого доступа к результатам запроса
Этот рецепт специально разработан для работы с результатами базы данных, а решение dtuple позволяет получить доступ к результатам по имени или индексному номеру.Это позволяет избежать необходимости доступа ко всему по нижнему индексу, который очень сложно поддерживать, как указано в вашем вопросе.
С кортежем всегда будет сложно добавлять или изменять поля.Вы правы, что словарь будет намного лучше.
Если вам нужно что-то с немного более дружественным синтаксисом, возможно, вы захотите взглянуть на ответы этот вопрос о простом "структурноподобном" объекте.Таким образом, вы можете передавать объект, скажем job
, и получить доступ к его полям еще проще , чем к кортежу или dict:
job.jobId, job.username = jobId, username
Если вы используете пакет MySQLdb, вы можете настроить свои объекты cursor так, чтобы они возвращали dicts вместо кортежей.
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 cursor
Как насчет этого:
class TypedTuple:
def __init__(self, fieldlist, items):
self.fieldlist = fieldlist
self.items = items
def __getattr__(self, field):
return self.items[self.fieldlist.index(field)]
Тогда вы могли бы сделать:
j = TypedTuple(["jobid", "label", "username"], job)
print j.jobid
Его должно быть легко поменять местами self.fieldlist.index(field)
с последующим поиском по словарю...просто отредактируйте свой __init__
метод!Что-то вроде того, что делает Стаале.