Более элегантный способ объявления нескольких переменных одновременно

Чтобы объявить несколько переменных одновременно, я бы сделал:

a, b = True, False

Но если бы мне пришлось объявлять гораздо больше переменных, это получается все менее и менее элегантно:

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True

Есть ли лучший/элегантный/удобный способ сделать это?

Это должно быть очень просто, но если бы я использовал список или кортеж для хранения переменных, как бы я подошел, чтобы быть полезным, так как:

aList = [a,b]

Не действует, я бы сделал:

a, b = True, True

Или чего мне не хватает?

Ответы

Ответ 1

Как и другие, маловероятно, что использование 10 разных локальных переменных с булевыми значениями - лучший способ написать вашу рутину (особенно, если у них действительно есть однобуквенные имена:)

В зависимости от того, что вы делаете, может быть смысл использовать словарь. Например, если вы хотите установить Boolean заданные значения для набора однобуквенных флагов, вы можете сделать это:

>>> flags = dict.fromkeys(["a", "b", "c"], True)
>>> flags.update(dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Если вы предпочитаете, вы также можете сделать это с помощью одного оператора присваивания:

>>> flags = dict(dict.fromkeys(["a", "b", "c"], True),
...              **dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Второй параметр dict не предназначен для этого: он действительно предназначен для того, чтобы вы могли переопределить отдельные элементы словаря, используя аргументы ключевых слов, такие как d=False. Приведенный выше код выдувает результат выражения, следующего за **, в набор аргументов ключевого слова, которые передаются вызываемой функции. Это, безусловно, надежный способ создания словарей, и люди, похоже, по крайней мере принимают эту идиому, но я подозреваю, что некоторые из них могут считать Unpythonic. </disclaimer>


Еще один подход, который, скорее всего, наиболее интуитивно понятен, если вы будете часто использовать этот шаблон, заключается в том, чтобы определить ваши данные как список значений флага (True, False), сопоставленных с именами флагов (односимвольный строки). Затем вы преобразовываете это определение данных в инвертированный словарь, который сопоставляет имена флагов значениям флагов. Это можно сделать довольно лаконично с помощью вложенного списка, но здесь очень понятная реализация:

>>> def invert_dict(inverted_dict):
...     elements = inverted_dict.iteritems()
...     for flag_value, flag_names in elements:
...         for flag_name in flag_names:
...             yield flag_name, flag_value
... 
>>> flags = {True: ["a", "b", "c"], False: ["d", "e"]}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Функция invert_dict представляет собой функцию генератора . Он генерирует или дает - значит, он многократно возвращает значения пар ключ-значение. Эти пары ключ-значение являются обратными для содержимого двух элементов исходного словаря flags. Они передаются в конструктор dict. В этом случае конструктор dict работает иначе, чем выше, потому что он кормит iterator, а не словарь как свой аргумент.


Рисунок на комментарии @Chris Lutz: если вы действительно будете использовать это для односимвольных значений, вы действительно можете сделать

>>> flags = {True: 'abc', False: 'de'}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Это работает, потому что строки Python iterable, что означает, что их можно перемещать по значению по значению. В случае строки значения представляют собой отдельные символы в строке. Поэтому, когда они интерпретируются как итеративные, так как в этом случае, когда они используются в цикле for, ['a', 'b', 'c'] и 'abc' фактически эквивалентны. Другим примером может быть, когда они передаются функции, которая принимает итерируемый, например tuple.

Я лично не сделал бы этого, потому что он не читал интуитивно: когда я вижу строку, я ожидаю, что она будет использоваться как одно значение, а не как список. Поэтому я смотрю на первую строчку и думаю: "Ладно, там есть флаг True и флаг False". Поэтому, хотя это возможно, я не думаю, что это путь. С другой стороны, это может помочь более четко объяснить концепции итераторов и итераторов.


Определение функции invert_dict, так что она фактически возвращает словарь, тоже неплохая идея; Я в основном просто не делал этого, потому что это не очень помогает объяснить, как работает рутина.


По-видимому, Python 2.7 имеет понимание словаря, что позволило бы предельно сжатым образом реализовать эту функцию. Это остается как упражнение для читателя, так как у меня нет установленного Python 2.7:)

Вы также можете комбинировать некоторые функции из универсального itertools модуля. Как говорится, Там больше, чем один способ сделать это. Подождите, люди Python этого не говорят. В любом случае, это правда. Я бы предположил, что Гвидо дал нам понимание в словаре, чтобы One Очевидный способ сделать это.

Ответ 2

a, b, c, d, e, g, h, i, j = (True,)*9
f = False

Ответ 3

Используйте список/словарь или определите свой собственный класс, чтобы инкапсулировать материал, который вы определяете, но если вам нужны все эти переменные, которые вы можете сделать:

a = b = c = d = e = g = h = i = j = True
f = False

Ответ 4

Это разработка на @Jeff M и мои комментарии.

Когда вы это сделаете:

a, b = c, d

Он работает с упаковкой и распаковкой кортежа. Вы можете разделить шаги упаковки и распаковки:

_ = c, d
a, b = _

Первая строка создает кортеж под названием _, который имеет два элемента, первый со значением c, а второй со значением d. Вторая строка распаковывает кортеж _ в переменные a и b. Это разрушает вашу огромную линию:

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True, True, True, True

В двух меньших строках:

_ = True, True, True, True, True, False, True, True, True, True
a, b, c, d, e, f, g, h, i, j = _

Он даст вам тот же результат, что и первая строка (включая одно и то же исключение, если вы добавите значения или переменные в одну часть, но забудьте обновить другую). Однако в этом конкретном случае yan answer является, пожалуй, лучшим.

Если у вас есть список значений, их можно распаковать. Вам просто нужно сначала преобразовать его в кортеж. Например, следующее присваивает значение от 0 до 9 каждому из a через j, соответственно:

a, b, c, d, e, f, g, h, i, j = tuple(range(10))

EDIT: аккуратный трюк, чтобы назначить все из них как true, кроме элемента 5 (переменная f):

a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))

Ответ 5

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

Вместо этого вы можете собрать их вместе в более крупную структуру данных, которая может быть сохранена в одной локальной переменной.

intuited показал, как вы можете использовать словарь для этого, и Крис Лутц показал, как использовать кортеж для временного хранения перед распаковкой в ​​отдельные переменные, но еще один вариант, который следует учитывать, - это использовать collections.namedtuple для более непрерывного связывания значений.

Итак, вы можете сделать что-то вроде:

# Define the attributes of our named tuple
from collections import namedtuple
DataHolder = namedtuple("DataHolder", "a b c d e f g")

# Store our data
data = DataHolder(True, True, True, True, True, False, True)

# Retrieve our data
print(data)
print(data.a, data.f)

Настоящий код, мы надеемся, будет использовать более значимые имена, чем "DataHolder" и буквы алфавита, конечно.

Ответ 6

Какая проблема, на самом деле?

Если вам действительно нужно или нужно 10 a, b, c, d, e , f, g, h, i, j, не будет другой возможности, в то время или в другой, написать a и написать b и написать c.....

Если значения все разные, вы будете обязаны писать для примера

a = 12
b= 'sun'
c = A() #(where A is a class)
d = range(1,102,5)
e = (line in filehandler if line.rstrip())
f = 0,12358
g = True
h = random.choice
i = re.compile('^(!=  ab).+?<span>')
j = [78,89,90,0]

то есть определяя "переменные" индивидуально.

Или, используя другое письмо, не нужно использовать _:

a,b,c,d,e,f,g,h,i,j =\
12,'sun',A(),range(1,102,5),\
(line for line in filehandler if line.rstrip()),\
0.12358,True,random.choice,\
re.compile('^(!=  ab).+?<span>'),[78,89,90,0]

или

a,b,c,d,e,f,g,h,i,j =\
(12,'sun',A(),range(1,102,5),
 (line for line in filehandler if line.rstrip()),
 0.12358,True,random.choice,
 re.compile('^(!=  ab).+?<span>'),[78,89,90,0])

.

Если некоторые из них должны иметь одинаковое значение, проблема в том, что слишком долго писать

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True 

?

Затем вы можете написать:

a=b=c=d=e=g=h=i=k=j=True
f = False

.

Я не понимаю, что именно ваша проблема. Если вы хотите написать код, вы обязаны использовать символы, необходимые для написания инструкций и определений. Что еще?

Интересно, ваш вопрос не является признаком того, что вы что-то неправильно понимаете.

Когда вы пишете a = 10, , вы не создаете переменную в смысле "кусок памяти, значение которой может измениться". Эта инструкция:

  • запускает создание объекта типа integer и значения 10 и привязки имени 'a' к этому объекту в текущем пространстве имен

  • или повторно назначьте имя "a" в пространстве имен объекту 10 (потому что "a" было привязано к другому объекту ранее)

Я говорю, потому что я не вижу, чтобы утилита определяла 10 идентификаторов a, b, c..., указывающих на False или True. Если эти значения не изменяются во время исполнения, почему 10 идентификаторов? И если они меняются, зачем сначала определять идентификаторы?, они будут созданы, когда это необходимо, если не определены ранее

Ваш вопрос кажется мне странным

Ответ 7

Похоже, вы приближаетесь к своей проблеме неправильно.

Перепишите свой код, чтобы использовать кортеж, или напишите класс для хранения всех данных.

Ответ 8

Мне нравится главный проголосовавший ответ; однако он имеет проблемы со списком, как показано.

  >> a, b = ([0]*5,)*2
  >> print b
  [0, 0, 0, 0, 0]
  >> a[0] = 1
  >> print b
  [1, 0, 0, 0, 0]

Это подробно обсуждается (здесь), но суть в том, что a и b - это тот же объект с возвратом a is b True (то же самое для id(a) == id(b)). Поэтому, если вы меняете индекс, вы меняете индекс как a, так и b, так как они связаны. Чтобы решить эту проблему, вы можете сделать (источник)

>> a, b = ([0]*5 for i in range(2))
>> print b
[0, 0, 0, 0, 0]
>> a[0] = 1
>> print b
[0, 0, 0, 0, 0]

Затем это можно использовать как вариант верхнего ответа, который имеет "желаемые" интуитивные результаты

>> a, b, c, d, e, g, h, i = (True for i in range(9))
>> f = (False for i in range(1)) #to be pedantic

Ответ 9

ну, вы могли бы сделать

а = Ь = с = d = False

Ответ 10

Как и в JavaScript, вы также можете использовать несколько операторов в одной строке в Python a = 1; b = "Hello World"; c += 3