Разделение кортежей в Python-лучшая практика?

У меня есть метод в моем коде Python, который возвращает кортеж - строку из SQL-запроса. Допустим, он имеет три поля: (jobId, label, username)

для удобства передачи его между функциями я передаю весь кортеж как переменную под названием "Работа". В конце концов, однако, я хочу добраться до битов, поэтому я использую такой код: (jobId, метка, имя пользователя) = job

Я понял, однако, что это кошмар обслуживания, потому что теперь я никогда не могу добавить новые поля в результирующий набор без нарушения всего существующего кода. Как я должен был это написать?

вот мои две лучшие догадки: (jobId, метка, имя пользователя) = (job[0], job[1], job[2]) ...но это не красиво когда у тебя 15...20 полей

или сразу преобразовать результаты из SQL-запроса в словарь и передать это (у меня нет контроля над тем, что он начинает жизнь как Кортеж, это исправлено для меня)

9 ответов


Я бы сказал, что словарь-это, безусловно, лучший способ сделать это. Он легко расширяется, позволяет дать каждому значению разумное имя, а Python имеет множество встроенных языковых функций для использования и управления словарями. Если вам нужно добавить больше полей позже, все, что вам нужно изменить, это код, который преобразует Кортеж в словарь, и код, который фактически использует новые значения.

например:

job={}
job['jobid'], job['label'], job['username']=<querycode>

@Staale

есть лучший способ:

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, вы можете настроить объекты курсора для возврата диктов вместо кортежей.

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__ способ! Что-то вроде Стаале.