Разделение кортежей в Python - лучшая практика?
У меня есть метод в моем коде Python, который возвращает кортеж - строку из SQL-запроса. Пусть говорят, что у него три поля: (jobId, label, username)
Для удобства передачи между функциями я передавал весь кортеж как переменную, называемую "job". В конце концов, однако, я хочу получить бит, поэтому я использовал код следующим образом:
(jobId, label, username) = job
Я понял, однако, что это кошмар для обслуживания, потому что теперь я никогда не могу добавлять новые поля в набор результатов, не нарушая весь существующий код. Как мне это написать?
Вот мои две лучшие догадки:
(jobId, label, username) = (задание [0], задание [1], задание [2])
... но это не масштабируется красиво, когда у вас 15... 20 полей
или сразу преобразовать результаты из SQL-запроса в словарь и передать его (я не контролирую тот факт, что он начинает жизнь как кортеж, который исправлен для меня)
Ответы
Ответ 1
Я бы сказал, что словарь, безусловно, лучший способ сделать это. Он легко расширяется, позволяет придать каждому значению разумное имя, а Python имеет множество встроенных языковых функций для использования и управления словарями. Если вам нужно добавить больше полей позже, все, что вам нужно изменить, это код, который преобразует кортеж в словарь и код, который фактически использует новые значения.
Например:
job={}
job['jobid'], job['label'], job['username']=<querycode>
Ответ 2
@Staale
Существует лучший способ:
job = dict(zip(keys, values))
Ответ 3
Это старый вопрос, но...
Я бы предложил использовать именованный кортеж в этой ситуации: collections.namedtuple
Это часть, в частности, что вы найдете полезным:
Подкласс не полезен для добавления новых сохраненных полей. Вместо этого просто создайте новый тип имен tuple из атрибута _fields.
Ответ 4
Возможно, это слишком много для вашего дела, но у меня возникнет соблазн создать класс "Job", который берет кортеж в качестве аргумента конструктора и имеет на нем соответствующие свойства. Затем я передавал бы экземпляры этого класса.
Ответ 5
Я бы использовал словарь. Вы можете преобразовать кортеж в словарь следующим образом:
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, поэтому может быть лучше, чем это сделать.
Ответ 6
Старый вопрос, но поскольку никто не упомянул об этом, я добавлю это из Поваренной книги Python:
Рецепт 81252: Использование dtuple для гибкого результата запроса результатов
Этот рецепт специально разработан для работы с результатами базы данных, а решение dtuple позволяет получить доступ к результатам по имени или номеру индекса. Это позволяет избежать доступа ко всему по индексу, который очень сложно поддерживать, как указано в вашем вопросе.
Ответ 7
С кортежем всегда будет сложно добавлять или изменять поля. Вы правы, что словарь будет намного лучше.
Если вы хотите что-то со слегка более дружественным синтаксисом, вы можете взглянуть на ответы на этот вопрос о простом "структурном" объекте. Таким образом вы можете обойти объект, скажем job
, и получить доступ к его полям еще проще, чем кортеж или dict:
job.jobId, job.username = jobId, username
Ответ 8
Если вы используете пакет MySQLdb, вы можете настроить объекты курсора для возврата 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
Ответ 9
Как насчет этого:
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__
! Что-то вроде Staale.