it-roy-ru.com

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

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

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

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

109
Trufa

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

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

>>> 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. Приведенный выше код взрывает результат выражения после ** в набор аргументов ключевого слова , которые передаются вызываемой функции. Это, безусловно, надежный способ создания словарей, и люди, кажется, по крайней мере принимают эту идиому, но я подозреваю, что некоторые могут считать ее непифонической. </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 является функцией генератора . Он генерирует или yields - это означает, что он многократно возвращает значения пар - ключ-значение. Эти пары ключ-значение являются инверсией содержимого двух элементов исходного словаря flags. Они подаются в конструктор dict. В этом случае конструктор dict работает не так, как описано выше, потому что в качестве аргумента ему подают итератор , а не словарь.


Опираясь на комментарий @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 не говорят этого. Ну, в любом случае это правда. Я бы предположил, что Гвидо дал нам словарное понимание, чтобы был Один очевидный путь сделать это.

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

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

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

Это разработка @ Джеффа М и моих комментариев.

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

a, b = c, d

Работает с упаковкой и распаковкой Tuple. Вы можете разделить этапы упаковки и распаковки:

_ = 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 = _

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

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

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

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

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

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

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

интуитивно показал, как вы можете использовать словарь для этого, а Крис Латс показал, как использовать кортеж для временного хранения перед распаковкой в ​​отдельные переменные, но другой вариант, который следует рассмотреть, - это использовать 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» и буквы алфавита, конечно.

5
ncoghlan

В чем проблема, на самом деле? 

Если вам действительно нужно или вы хотите 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» в пространстве имен для объекта 10 (потому что «a» был предварительно связан с другим объектом)

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

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

4
eyquem

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

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

2
richo

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

  >> 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
0
Novice C